Data Summary:

This dataset was generated by our group, which can be downloaded from GEO (GSE146974) or or https://drive.google.com/file/d/1kR8Hhufoo2h2OtomW8n3kM0gaQhVS564/view?usp=sharing. This dataset was generated from human peripheral blood mononuclear clear cells by Ficoll Separation followed by CD14 and CD16 positive cell selection. Since the CD14 and CD16 antibodies are not 100% specific, some T cells were also present in the scRNA-seq data. We performed clustering analysis using leiden’s algorithm for each batch and identified 288 T cells in total based on the T cell marker genes CD3D, CD3E and CD3G. Aftering removing these 288 T cells, there are 10,878 cells and 21,289 genes, which was processed and sequenced at three different days, resulting in three batches (3,640 cells in T1, 4,833 cells in T2 and 2,405 cells in T3) left in the remaining analysis.

Human monocyte preparation: Monocyte preparation uses a modification of published protocols. Briefly, ~20 ml blood drawn in sodium heparin was processed immediately in the lab in the Clinical Research Center at Columbia University. PBMCs were isolated by gradient Ficoll paque centrifugation, which maintains cell viability and prevents ex vivo activation during cell recovery. Cells were stained with antibodies against human HLADR, CD14 and CD16 and monocyte subsets defined as HLADR+CD14++CD16-(classical), HLADR+CD14++CD16+ (intermediate), HLADR+CD14dim/CD16++ (nonclassical, patrolling monocyte). DAPI staining was used to exclude dead cells. Monocytes were sorted by a BD Influx Sorter into tubes for real-time 10x Genomics analysis.

1 Summary

Here I used monocle3 (monocle3_0.2.1) to conduct the pseudotime analysis.

CarDEC, scVI and DCA are both deep learning based methods. For each method, we used all genes as the input, the way of Using latetnOne is the standard pipline for monocle3 (denosied count -> normalization -> scaling -> pca dimension reduction -> umap visualization based on pca dimension reduction) and the other method replces the pca by the latent representation and then umap visualization based on latent representation.

============================================================================================

options(warn=-1) # turn off warning message globally
.libPaths(c("/home/xiaoxiang/R/x86_64-pc-linux-gnu-library/3.5",.libPaths()))
Sys.setenv(RETICULATE_PYTHON_ENV="/home/xiaoxiang/anaconda3/envs/py36")#="/home/xiaoxiang/.conda/envs/DESCVIR"
Sys.setenv(RETICULATE_PYTHON="/usr/bin/python3")
#RETICULATE_PYTHON="/home/xiaoxiang/anaconda3/bin/python3",
if ("Seurat" %in% loadedNamespaces()) detach("package:Seurat",unload = T)
dyn.load("/home/xiaoxiang/R/x86_64-pc-linux-gnu-library/3.5/sf/libs/sf.so")
#suppressPackageStartupMessages(library(monocle,lib.loc = "/usr/lib/R/monocle_alpha"))# devtools::install_github("")
#devtools::install_github("cole-trapnell-lab/DDRTree", ref="simple-ppt-like",lib="/usr/lib/R/monocle_alpha")
#devtools::install_github("r-spatial/sf") if 
#install.packages("~/Downloads/monocle-release-monocle3_alpha/", repos = NULL,lib = "/usr/lib/R/monocle_alpha")
suppressPackageStartupMessages(library(reticulate))
#suppressPackageStartupMessages(library(devtools))
suppressPackageStartupMessages(library(monocle3))
#suppressPackageStartupMessages(library(flexclust))
#suppressPackageStartupMessages(library(mcclust))
suppressPackageStartupMessages(library(dplyr))
suppressPackageStartupMessages(library(ggjoy))
suppressPackageStartupMessages(library(VGAM))
suppressPackageStartupMessages(library(knitr))
suppressPackageStartupMessages(library(ggplot2))
suppressPackageStartupMessages(library(kableExtra))
#py_install('umap-learn', pip = T, pip_ignore_installed = T)
#import("leiden")
#fig_path="/home/xiaoxiang/Documents/DESC_paper_prepare/DESC_paper_final/formal_revised/figures_sep/"
datadirpath="./"
df_pseudotime_list=list()
# load necessay function
#source("/media/xiaoxiang/D/DESC_reproducible_file/helpfunc_new.R")
#source("/media/xiaoxiang/D/Upenn_computer_backup/Documents/Human_Heart_Project/heart/Heart_result_updated/helpfunc_new.R")
old=theme_set(theme_bw()+theme(strip.background = element_rect(fill="white"),
                                         panel.background = element_blank(),
                               legend.background = element_blank(),
                                         panel.grid =element_blank()))
BatchKL=function(df,dimensionData=NULL,replicates=200,n_neighbors=100,n_cells=100,batch="BatchID"){
  #entropy of batch mixiing
  #replicates is the number of boostrap times
  #n_neighbors is the number of nearest neighbours of cell(from all batchs)
  #n_cells is the number of randomly picked cells
  if (is.null(dimensionData)){
        tsnedata=as.matrix(df[,c("tSNE_1","tSNE_2")])
  }else{
        tsnedata=as.matrix(dimensionData)
  }
  batchdata=factor(as.vector(df[,batch]))
  table.batchdata=as.matrix(table(batchdata))[,1]
  tmp00=table.batchdata/sum(table.batchdata)#proportation of population
  n=dim(df)[1]
  KL=sapply(1:replicates,function(x){
    bootsamples=sample(1:n,n_cells)
    #nearest=nn2(tsnedata,tsnedata[bootsamples,],k=n_neighbors)
    nearest=nabor::knn(tsnedata,tsnedata[bootsamples,],k=min(5*length(tmp00),n_neighbors))
    KL_x=sapply(1:length(bootsamples),function(y){
      id=nearest$nn.idx[y,]
      tmp=as.matrix(table(batchdata[id]))[,1]
      tmp=tmp/sum(tmp)
      return(sum(tmp*log2(tmp/tmp00),na.rm = T))
    })
    return(mean(KL_x,na.rm = T))
  })
  return(KL)
}
Convert_to_seurat3=function(adata){
  suppressPackageStartupMessages(library("Seurat",lib.loc = "/usr/lib/R/self_library/"))
  mtx=py_to_r(adata$X$T$tocsc())
  cellinfo=py_to_r(adata$obs)
  geneinfo=py_to_r(adata$var)
  colnames(mtx)=cellinfo$cellname
  rownames(mtx)=rownames(geneinfo)
  obj=CreateSeuratObject(mtx,meta.data = cellinfo[,!colnames(cellinfo)%in%c("n_genes","n_counts"),drop=F],min.features  = 1)
  return(obj)
}
getwd()
[1] "/home/xiaoxiang/Documents/carDEC_paper/CarDEC_new20200421/results_rmarkdown"
get_plot4=function(df00){
  p1=ggplot()+geom_point(data =df00,aes(x=UMAP_1,y=UMAP_2,color=FCGR3A),size=0.01)+
    scale_color_gradient(low="grey",high="red")+
    theme(legend.position = "top")+
    guides(color=guide_colorbar(title.vjust = 0.7))
  
  p2=ggplot()+geom_point(data =df00,aes(x=UMAP_1,y=UMAP_2,color=S100A8),size=0.01)+
    scale_color_gradient(low="grey",high="red")+
    theme(legend.position = "top")+
     guides(color=guide_colorbar(title.vjust = 0.7))
  
  p3=ggplot(data =df00,aes(x=pseudotime,y=FCGR3A))+
      geom_point(aes(color=BatchID),size=0.01)+
      guides(color=guide_legend(override.aes = list(size=5)))+
      geom_smooth(aes(color=BatchID),method="gam",formula = y ~ s(x, bs="cs"))+
       geom_smooth(color="black",method="gam",formula = y ~ s(x, bs="cs"),size=0.5)+
      ggtitle("")+xlab("Pseudotime")+theme(legend.position = "top",
                               plot.title = element_text(size=18,face="bold",hjust=0.5),
                               legend.text = element_text(size=15,face="bold"),
                               plot.margin = unit(c(0,1,0,0),"cm"),
                               legend.title = element_blank())+
    scale_color_brewer(palette = "Set2")
  
  p4=ggplot(data =df00,aes(x=pseudotime,y=S100A8))+
      geom_point(aes(color=BatchID),size=0.01)+
      guides(color=guide_legend(override.aes = list(size=5)))+
      geom_smooth(aes(color=BatchID),method="gam",formula = y ~ s(x, bs="cs"))+
       geom_smooth(color="black",method="gam",formula = y ~ s(x, bs="cs"),size=0.5)+
      ggtitle("")+xlab("Pseudotime")+theme(legend.position = "top",
                               plot.title = element_text(size=18,face="bold",hjust=0.5),
                               legend.text = element_text(size=15,face="bold"),
                               legend.title = element_blank())+scale_color_brewer(palette = "Set2")
  
  p=egg::ggarrange(p1,p3,p2,p4,ncol=4,draw=F)
  return(p)
}
get_plot4_sep=function(df00){
  p1=ggplot()+geom_point(data =df00,aes(x=UMAP_1,y=UMAP_2,color=FCGR3A),size=0.01)+
    scale_color_gradient(low="grey",high="red")+
    theme(legend.position = "top")+
    guides(color=guide_colorbar(title.vjust = 0.7))
  
  p2=ggplot()+geom_point(data =df00,aes(x=UMAP_1,y=UMAP_2,color=S100A8),size=0.01)+
    scale_color_gradient(low="grey",high="red")+
    theme(legend.position = "top")+
     guides(color=guide_colorbar(title.vjust = 0.7))
  
  p3=ggplot(data =df00,aes(x=pseudotime,y=FCGR3A))+
      geom_point(aes(color=BatchID),size=0.05)+
      guides(color=guide_legend(override.aes = list(size=5)))+
      geom_smooth(aes(color=BatchID),method="gam",formula = y ~ s(x, bs="cs"))+
       geom_smooth(color="black",method="gam",formula = y ~ s(x, bs="cs"),size=0.5)+
      ggtitle("")+xlab("Pseudotime")+theme(legend.position = "top",
                               plot.title = element_text(size=18,face="bold",hjust=0.5),
                               legend.text = element_text(size=15,face="bold"),
                               #plot.margin = unit(c(0,1,0,0),"cm"),
                               legend.title = element_blank())+
    scale_color_brewer(palette = "Set2")
  p4=ggplot(data =df00,aes(x=pseudotime,y=S100A8))+
      geom_point(aes(color=BatchID),size=0.05)+
      guides(color=guide_legend(override.aes = list(size=5)))+
      geom_smooth(aes(color=BatchID),method="gam",formula = y ~ s(x, bs="cs"))+
       geom_smooth(color="black",method="gam",formula = y ~ s(x, bs="cs"),size=0.5)+
      ggtitle("")+xlab("Pseudotime")+theme(legend.position = "top",
                               plot.title = element_text(size=18,face="bold",hjust=0.5),
                               legend.text = element_text(size=15,face="bold"),
                               legend.title = element_blank())+
    scale_color_brewer(palette = "Set2")
  return(list(p1,p2,p3,p4))
}
ad=import("anndata",convert = FALSE)
/home/xiaoxiang/.local/lib/python3.6/site-packages/dask/config.py:161: YAMLLoadWarning: calling yaml.load() without Loader=... is deprecated, as the default Loader is unsafe. Please read https://msg.pyyaml.org/load for full details.
  data = yaml.load(f.read()) or {}
adata=ad$read_h5ad("../../dca_test.h5ad")
obj0=Convert_to_seurat3(adata)
obj0=NormalizeData(obj0,verbose = F)
raw.data=obj0@assays$RNA@counts
maprules=c("2017_0801"="T1","2017_1017"="T2","2017_1120"="T3")
maprules
2017_0801 2017_1017 2017_1120 
     "T1"      "T2"      "T3" 

Here we compared different methods, including DCA and scVI.

hvg_genes=read.table("../final_processed_results/CarDEC_hvg_used.tsv",header = T,sep="\t",stringsAsFactors = F)
hvg_genes=subset(hvg_genes,Variance.Type=="HVG") #top 2000 genes 

2 Monocle3 for raw data

2.1 HVGs raw

rr cell.meta.data=obj0@meta.data cell.meta.data\(dataset_batch=plyr::mapvalues(cell.meta.data\)batch_label,names(maprules),maprules) gene_ann=data.frame(gene_short_name = make.unique(rownames(raw.data)),row.names = make.unique(rownames(raw.data))) #pd <- new(,data=cell.meta.data) #fd <- new(,data=gene_ann) cds <- new_cell_data_set(raw.data[rownames(raw.data)%in%hvg_genes$genename,], cell_metadata = cell.meta.data, gene_metadata =gene_ann[gene_ann\(gene_short_name%in%hvg_genes\)genename,,drop=F]) ## Step 1: Normalize and pre-process the data cds <- preprocess_cds(cds, num_dim = 32,method=,norm_method=,verbose = F)

multiple methods tables found for ‘type’

rr ## Step 2: Remove batch effects with cell alignment ##cds <- align_cds(cds, alignment_group = , residual_model_formula_str = NULL) ## Step 3: Reduce the dimensions using UMAP cds <- reduce_dimension(cds,reduction_method = ,preprocess_method=,verbose = F) ## Step 4: Cluster the cells cds <- cluster_cells(cds,reduction_method =,cluster_method = ,verbose = F) # Construct the graph # Note that, for the rest of the code to run, the graph should be fully (partionly) connected ## Step 5: Learn a graph cds <- learn_graph(cds, use_partition = T,verbose = F)


  |                                                                                                                                                
  |                                                                                                                                          |   0%
  |                                                                                                                                                
  |==========================================================================================================================================| 100%

  |                                                                                                                                                
  |                                                                                                                                          |   0%
  |                                                                                                                                                
  |==========================================================================================================================================| 100%

rr colData(cds)\(clusters=cds@clusters\)UMAP$clusters p1=plot_cells(cds,color_cells_by = ,label_cell_groups = F)+theme(legend.position = ) p2=plot_cells(cds,color_cells_by = ,label_cell_groups=F,graph_label_size=2, label_leaves=F,label_branch_points=F)+theme(legend.position = ) p=cowplot::plot_grid(p1,p2,align = ,ncol = 3)

rr p

rr ## Step 6: Order cells # a helper function to identify the root principal points: get_earliest_principal_node <- function(cds, cluster=c(,)){ root_pr_nodes=sapply(cluster,function(ii){ cell_ids <- which(colData(cds)[, ] %in%ii)

closest_vertex <-cds@principal_graph_aux[[]]$pr_graph_cell_proj_closest_vertex

closest_vertex <- as.matrix(closest_vertex[colnames(cds), ]) root_pr_nodes <-igraph::V(principal_graph(cds)[[]])$name[as.numeric(names(which.max(table(closest_vertex[cell_ids,]))))] }) root_pr_nodes } # root cells ids=get_earliest_principal_node(cds,cluster=c(,,)) cds <- order_cells(cds,root_pr_nodes = ids) #plot_cells(cds,color_cells_by = )

rr colData(cds)\(pseudotime=pseudotime(cds) colData(cds)\)Pseudotime=colData(cds)\(pseudotime/max(colData(cds)\)pseudotime,na.rm = T) df_den=pData(cds)[,c(,_batch)] df_den=as.data.frame(df_den[!is.infinite(df_den$Pseudotime),]) set.seed(10) theme_use=theme(legend.text = element_text(size=16), legend.title = element_text(size=20)) p_ori_1=plot_cells(cds,color_cells_by = _batch,graph_label_size=0,alpha=1,cell_size = 0.6)+ guides(colour = guide_legend(override.aes = list(alpha=0.7, size=5)))+ theme_use+ theme(legend.position = )+theme(legend.title = element_blank())

p_ori_2=plot_cells(cds,color_cells_by = ,label_branch_points=T,graph_label_size=2,alpha=1,cell_size = 0.6)+ theme(legend.position = , legend.title = element_text(vjust = 0.2), legend.text = element_text(angle=-50 ), legend.key.height = unit(0.5,), legend.key.width = unit(1,))+ guides(color = guide_colourbar(label.position = ))+theme_use

Cells aren't colored in a way that allows them to be grouped.

rr p_ori_3=ggplot(data=df_den)+geom_density(aes(x=Pseudotime,fill=dataset_batch),alpha=0.7)+ scale_y_continuous(expand = c(0,0))+ scale_x_continuous(expand = c(0,0))+ theme(legend.position=)+theme_use p_monocle_ori=egg::ggarrange(p_ori_1,p_ori_2,p_ori_3,ncol=3,draw=F)

rr # printed how many cells with no pseudotime table(as.numeric(is.infinite(pData(cds)[,c()]))) #0 mean normal pseudotime and 1 means infinity.


    0 
10878 

rr p_monocle_ori

rr cds_exprs=FetchData(obj0,vars = c(3A,100A8)) df0=data.frame(cbind(pseudotime=pData(cds)\(Pseudotime,cds_exprs)) #cds_exprs=as.matrix(SingleCellExperiment::counts(cds)[c(\FCGR3A\,\S100A8\),]) #df0=data.frame(cbind(pseudotime=pData(cds)\)Pseudotime,log1p(t(cds_exprs)/size_factors(cds)))) df0\(UMAP_1=reducedDims(cds)\)UMAP[,1] df0\(UMAP_2=reducedDims(cds)\)UMAP[,2] df0\(BatchID=pData(cds)\)dataset_batch df0=df0[is.finite(df0$pseudotime),] df0=df0[order(df0$pseudotime,decreasing = F),,drop=F] df0\(x=df0\)pseudotime/max(df0\(pseudotime) df_pseudotime_list\)raw=df0

  • Feature plots of FCGR3A and S100A8

rr p=get_plot4(df00 = df0)

rr p

rr df_den=colData(cds) tt1=ks.test(df_den\(Pseudotime[df_den\)dataset_batch==1],df_den\(Pseudotime[df_den\)dataset_batch==3])

p-value will be approximate in the presence of ties

rr tt1


    Two-sample Kolmogorov-Smirnov test

data:  df_den$Pseudotime[df_den$dataset_batch == \T1\] and df_den$Pseudotime[df_den$dataset_batch == \T3\]
D = 0.57211, p-value < 2.2e-16
alternative hypothesis: two-sided

rr tt2=ks.test(df_den\(Pseudotime[df_den\)dataset_batch==1],df_den\(Pseudotime[df_den\)dataset_batch==2])

p-value will be approximate in the presence of ties

rr tt2


    Two-sample Kolmogorov-Smirnov test

data:  df_den$Pseudotime[df_den$dataset_batch == \T1\] and df_den$Pseudotime[df_den$dataset_batch == \T2\]
D = 0.4611, p-value < 2.2e-16
alternative hypothesis: two-sided

rr tt3=ks.test(df_den\(Pseudotime[df_den\)dataset_batch==2],df_den\(Pseudotime[df_den\)dataset_batch==3]) tt3


    Two-sample Kolmogorov-Smirnov test

data:  df_den$Pseudotime[df_den$dataset_batch == \T2\] and df_den$Pseudotime[df_den$dataset_batch == \T3\]
D = 0.70922, p-value < 2.2e-16
alternative hypothesis: two-sided

rr Stable5[1,2:4]=matrix(get_p_new(c(tt1\(p.value,tt2\)p.value,tt3\(p.value),c(tt1\)statistic,tt2\(statistic,tt3\)statistic)),1,3)

2.2 All genes raw

cell.meta.data=obj0@meta.data
cell.meta.data$dataset_batch=plyr::mapvalues(cell.meta.data$batch_label,names(maprules),maprules)
gene_ann=data.frame(gene_short_name = make.unique(rownames(raw.data)),row.names = make.unique(rownames(raw.data)))
#pd <- new("AnnotatedDataFrame",data=cell.meta.data)
#fd <- new("AnnotatedDataFrame",data=gene_ann)
cds <- new_cell_data_set(raw.data, cell_metadata = cell.meta.data,gene_metadata =gene_ann)
## Step 1: Normalize and pre-process the data
cds <- preprocess_cds(cds, num_dim = 32,method="PCA",norm_method="log",verbose = F)
## Step 2: Remove batch effects with cell alignment
##cds <- align_cds(cds, alignment_group = "BatchID", residual_model_formula_str = NULL)
## Step 3: Reduce the dimensions using UMAP
cds <- reduce_dimension(cds,reduction_method = "UMAP",preprocess_method="PCA",verbose = F)

## Step 4: Cluster the cells
cds <- cluster_cells(cds,reduction_method ="UMAP",cluster_method = "leiden",verbose = F)
# Construct the graph
# Note that, for the rest of the code to run, the graph should be fully (partionly) connected
## Step 5: Learn a graph
cds <- learn_graph(cds, use_partition = T,verbose = F)
colData(cds)$clusters=cds@clusters$UMAP$clusters
p1=plot_cells(cds,color_cells_by = "partition",label_cell_groups = F)+theme(legend.position = "top")
p2=plot_cells(cds,color_cells_by = "clusters",label_cell_groups=F,graph_label_size=2, label_leaves=F,label_branch_points=F)+theme(legend.position = "top")
p=cowplot::plot_grid(p1,p2,align = "h",ncol = 3)

rr p

rr ## Step 6: Order cells # a helper function to identify the root principal points: get_earliest_principal_node <- function(cds, cluster=c(,)){ root_pr_nodes=sapply(cluster,function(ii){ cell_ids <- which(colData(cds)[, ] %in%ii)

closest_vertex <-cds@principal_graph_aux[[]]$pr_graph_cell_proj_closest_vertex

closest_vertex <- as.matrix(closest_vertex[colnames(cds), ]) root_pr_nodes <-igraph::V(principal_graph(cds)[[]])$name[as.numeric(names(which.max(table(closest_vertex[cell_ids,]))))] }) root_pr_nodes } # root cells ids=get_earliest_principal_node(cds,cluster=c(,)) cds <- order_cells(cds,root_pr_nodes = ids) #plot_cells(cds,color_cells_by = )

rr colData(cds)\(pseudotime=pseudotime(cds) colData(cds)\)Pseudotime=colData(cds)\(pseudotime/max(colData(cds)\)pseudotime,na.rm = T) df_den=pData(cds)[,c(,_batch)] df_den=as.data.frame(df_den[!is.infinite(df_den$Pseudotime),]) set.seed(10) theme_use=theme(legend.text = element_text(size=16), legend.title = element_text(size=20)) p_ori_all_1=plot_cells(cds,color_cells_by = _batch,graph_label_size=0,alpha=1,cell_size = 0.6)+ guides(colour = guide_legend(override.aes = list(alpha=0.7, size=5)))+ theme_use+ theme(legend.position = )+theme(legend.title = element_blank())

p_ori_all_2=plot_cells(cds,color_cells_by = ,label_branch_points=T,graph_label_size=2,alpha=1,cell_size = 0.6)+ theme(legend.position = , legend.title = element_text(vjust = 0.2), legend.text = element_text(angle=-50 ), legend.key.height = unit(0.5,), legend.key.width = unit(1,))+ guides(color = guide_colourbar(label.position = ))+theme_use

Cells aren't colored in a way that allows them to be grouped.

rr p_ori_all_3=ggplot(data=df_den)+geom_density(aes(x=Pseudotime,fill=dataset_batch),alpha=0.7)+ scale_y_continuous(expand = c(0,0))+ scale_x_continuous(expand = c(0,0))+ theme(legend.position=)+theme_use p_monocle_ori_all=egg::ggarrange(p_ori_all_1,p_ori_all_2,p_ori_all_3,ncol=3,draw=F)

rr # printed how many cells with no pseudotime table(as.numeric(is.infinite(pData(cds)[,c()]))) #0 mean normal pseudotime and 1 means infinity.


    0 
10878 

rr p_monocle_ori_all

rr cds_exprs=FetchData(obj0,vars = c(3A,100A8)) df0=data.frame(cbind(pseudotime=pData(cds)\(Pseudotime,cds_exprs)) #cds_exprs=as.matrix(SingleCellExperiment::counts(cds)[c(\FCGR3A\,\S100A8\),]) #df0=data.frame(cbind(pseudotime=pData(cds)\)Pseudotime,log1p(t(cds_exprs)/size_factors(cds)))) df0\(UMAP_1=reducedDims(cds)\)UMAP[,1] df0\(UMAP_2=reducedDims(cds)\)UMAP[,2] df0\(BatchID=pData(cds)\)dataset_batch df0=df0[is.finite(df0$pseudotime),] df0=df0[order(df0$pseudotime,decreasing = F),,drop=F] df0\(x=df0\)pseudotime/max(df0\(pseudotime) df_pseudotime_list\)raw_all=df0

  • Feature plots of FCGR3A and S100A8

rr p=get_plot4(df00 = df0)

rr p

rr df_den=colData(cds) tt1=ks.test(df_den\(Pseudotime[df_den\)dataset_batch==1],df_den\(Pseudotime[df_den\)dataset_batch==3])

p-value will be approximate in the presence of ties

rr tt1


    Two-sample Kolmogorov-Smirnov test

data:  df_den$Pseudotime[df_den$dataset_batch == \T1\] and df_den$Pseudotime[df_den$dataset_batch == \T3\]
D = 0.92486, p-value < 2.2e-16
alternative hypothesis: two-sided

rr tt2=ks.test(df_den\(Pseudotime[df_den\)dataset_batch==1],df_den\(Pseudotime[df_den\)dataset_batch==2]) tt2


    Two-sample Kolmogorov-Smirnov test

data:  df_den$Pseudotime[df_den$dataset_batch == \T1\] and df_den$Pseudotime[df_den$dataset_batch == \T2\]
D = 0.68425, p-value < 2.2e-16
alternative hypothesis: two-sided

rr tt3=ks.test(df_den\(Pseudotime[df_den\)dataset_batch==2],df_den\(Pseudotime[df_den\)dataset_batch==3])

p-value will be approximate in the presence of ties

rr tt3


    Two-sample Kolmogorov-Smirnov test

data:  df_den$Pseudotime[df_den$dataset_batch == \T2\] and df_den$Pseudotime[df_den$dataset_batch == \T3\]
D = 0.77509, p-value < 2.2e-16
alternative hypothesis: two-sided

rr Stable5[2,2:4]=matrix(get_p_new(c(tt1\(p.value,tt2\)p.value,tt3\(p.value),c(tt1\)statistic,tt2\(statistic,tt3\)statistic)),1,3)

3 Monocle3 using carDEC

In this section, we will evalutate the performance of carDEC.

Note that: carDEC used all genes and extracted HVG to evaluate.

rr adata=ad$read_h5ad(../final_processed_results/CarDEC Results/adata_CarDEC.h5ad)

rr cell.meta.data=py_to_r(adata\(obs) cell.meta.data\)dataset_batch=plyr::mapvalues(cell.meta.data\(batch_label,names(maprules),maprules) gene_ann0=py_to_r(adata\)var) gene_ann=data.frame(gene_short_name = make.unique(rownames(gene_ann0)), VarianceType=gene_ann0\(`Variance Type`, row.names = make.unique(rownames(gene_ann0))) mtx=t(py_to_r(adata\)layers[‘denoised counts’])) colnames(mtx)=cell.meta.data$cellname rownames(mtx)=rownames(gene_ann) mtx_sizefactor=1e4/colSums(mtx)

3.1 Using latent

cds <- new_cell_data_set(mtx, cell_metadata = cell.meta.data,gene_metadata =gene_ann)
## Step 1: Normalize and pre-process the data
cds <- preprocess_cds(cds, num_dim = 32,method="PCA",norm_method="log",verbose = F)

tmp0=py_to_r(adata$obsm["embedding"])
colnames(tmp0)=paste0("PC",1:ncol(tmp0))
reducedDims(cds)$PCA=tmp0

## Step 2: Remove batch effects with cell alignment
##cds <- align_cds(cds, alignment_group = "BatchID", residual_model_formula_str = NULL)
## Step 3: Reduce the dimensions using UMAP
cds <- reduce_dimension(cds,reduction_method = "UMAP",preprocess_method="PCA",verbose = F)

## Step 4: Cluster the cells
cds <- cluster_cells(cds,reduction_method ="UMAP",cluster_method = "leiden",verbose = F)

# Construct the graph
# Note that, for the rest of the code to run, the graph should be fully (partionly) connected
## Step 5: Learn a graph
cds <- learn_graph(cds, use_partition = T,verbose = F)
colData(cds)$clusters=cds@clusters$UMAP$clusters
p1=plot_cells(cds,color_cells_by = "partition",label_cell_groups = F)+theme(legend.position = "top")
p2=plot_cells(cds,color_cells_by = "clusters",label_cell_groups=F,graph_label_size=2, label_leaves=F,label_branch_points=F)+theme(legend.position = "top")
p=cowplot::plot_grid(p1,p2,align = "h",ncol = 3)

rr p

rr ## Step 6: Order cells # root cells ids=get_earliest_principal_node(cds,cluster=c()) cds <- order_cells(cds, root_pr_nodes=ids) plot_cells(cds,color_cells_by = )

Cells aren't colored in a way that allows them to be grouped.

rr colData(cds)\(pseudotime=pseudotime(cds) colData(cds)\)Pseudotime=colData(cds)\(pseudotime/max(colData(cds)\)pseudotime,na.rm = T) df_den=pData(cds)[,c(,_batch)] df_den=as.data.frame(df_den[!is.infinite(df_den$Pseudotime),]) set.seed(10) theme_use=theme(legend.text = element_text(size=16), legend.title = element_text(size=20)) p_carDEC_latent_1=plot_cells(cds,color_cells_by = _batch,,graph_label_size=0,alpha=1,cell_size = 0.6)+ guides(colour = guide_legend(override.aes = list(alpha=0.7, size=5)))+ theme_use+ theme(legend.position = )

p_carDEC_latent_2=plot_cells(cds,color_cells_by = ,label_branch_points=T,graph_label_size=2,alpha=1,cell_size = 0.6)+ theme(legend.position = , legend.title = element_text(vjust = 0.2), legend.text = element_text(angle=-50 ), legend.key.height = unit(0.5,), legend.key.width = unit(1,))+ guides(color = guide_colourbar(label.position = ))+theme_use

Cells aren't colored in a way that allows them to be grouped.

rr p_carDEC_latent_3=ggplot(data=df_den)+geom_density(aes(x=Pseudotime,fill=dataset_batch),alpha=0.7)+ scale_y_continuous(expand = c(0,0))+ scale_x_continuous(expand = c(0,0))+ theme(legend.position=)+theme_use p_monocle_carDEC_latent=egg::ggarrange(p_carDEC_latent_1,p_carDEC_latent_2,p_carDEC_latent_3,ncol=3,draw=F)

rr p_monocle_carDEC_latent

rr #cds_exprs=FetchData(obj0,vars = c(3A,100A8)) #df0=data.frame(cbind(pseudotime=pData(cds)\(Pseudotime,cds_exprs))=1e4/rowSums(mtx) cds_exprs=as.matrix(SingleCellExperiment::counts(cds)[c(\FCGR3A\,\S100A8\),]) df0=data.frame(cbind(pseudotime=pData(cds)\)Pseudotime,log1p(t(cds_exprs)*mtx_sizefactor))) df0\(UMAP_1=reducedDims(cds)\)UMAP[,1] df0\(UMAP_2=reducedDims(cds)\)UMAP[,2] df0\(BatchID=pData(cds)\)dataset_batch df0=df0[is.finite(df0$pseudotime),] df0=df0[order(df0$pseudotime,decreasing = F),,drop=F] df0\(x=df0\)pseudotime/max(df0\(pseudotime) df_pseudotime_list\)carDEC_latent=df0

  • Feature plots of FCGR3A and S100A8

rr p=get_plot4(df00 = df0)

rr p

rr df_den=colData(cds) tt1=ks.test(df_den\(Pseudotime[df_den\)dataset_batch==1],df_den\(Pseudotime[df_den\)dataset_batch==3]) tt1


    Two-sample Kolmogorov-Smirnov test

data:  df_den$Pseudotime[df_den$dataset_batch == \T1\] and df_den$Pseudotime[df_den$dataset_batch == \T3\]
D = 0.051982, p-value = 0.0007981
alternative hypothesis: two-sided

rr tt2=ks.test(df_den\(Pseudotime[df_den\)dataset_batch==1],df_den\(Pseudotime[df_den\)dataset_batch==2]) tt2


    Two-sample Kolmogorov-Smirnov test

data:  df_den$Pseudotime[df_den$dataset_batch == \T1\] and df_den$Pseudotime[df_den$dataset_batch == \T2\]
D = 0.033595, p-value = 0.01843
alternative hypothesis: two-sided

rr tt3=ks.test(df_den\(Pseudotime[df_den\)dataset_batch==2],df_den\(Pseudotime[df_den\)dataset_batch==3]) tt3


    Two-sample Kolmogorov-Smirnov test

data:  df_den$Pseudotime[df_den$dataset_batch == \T2\] and df_den$Pseudotime[df_den$dataset_batch == \T3\]
D = 0.052437, p-value = 0.0002922
alternative hypothesis: two-sided

rr Stable5[3,2:4]=matrix(get_p_new(c(tt1\(p.value,tt2\)p.value,tt3\(p.value),c(tt1\)statistic,tt2\(statistic,tt3\)statistic)),1,3)

3.2 HVGs denoised

cds <- new_cell_data_set(mtx[gene_ann$VarianceType=="HVG",], cell_metadata = cell.meta.data,gene_metadata =gene_ann[gene_ann$VarianceType=="HVG",,drop=F])
## Step 1: Normalize and pre-process the data
cds <- preprocess_cds(cds, num_dim = 32,method="PCA",norm_method="log")

## Step 2: Remove batch effects with cell alignment
##cds <- align_cds(cds, alignment_group = "BatchID", residual_model_formula_str = NULL)
## Step 3: Reduce the dimensions using UMAP
cds <- reduce_dimension(cds,reduction_method = "UMAP",preprocess_method="PCA",verbose = F)

## Step 4: Cluster the cells
cds <- cluster_cells(cds,reduction_method ="UMAP",cluster_method = "leiden",verbose = F)

# Construct the graph
# Note that, for the rest of the code to run, the graph should be fully (partionly) connected
## Step 5: Learn a graph
cds <- learn_graph(cds, use_partition = T,verbose = F)
colData(cds)$clusters=cds@clusters$UMAP$clusters
p1=plot_cells(cds,color_cells_by = "partition",label_cell_groups = F)+theme(legend.position = "top")
p2=plot_cells(cds,color_cells_by = "clusters",label_cell_groups=F,graph_label_size=2, label_leaves=F,label_branch_points=F)+theme(legend.position = "top")
p=cowplot::plot_grid(p1,p2,align = "h",ncol = 3)

rr p

rr ## Step 6: Order cells # root cells ids=get_earliest_principal_node(cds,cluster=c()) cds <- order_cells(cds, root_pr_nodes=ids) #plot_cells(cds,color_cells_by = )

rr colData(cds)\(pseudotime=pseudotime(cds) colData(cds)\)Pseudotime=colData(cds)\(pseudotime/max(colData(cds)\)pseudotime,na.rm = T) df_den=pData(cds)[,c(,_batch)] df_den=as.data.frame(df_den[!is.infinite(df_den$Pseudotime),]) set.seed(10) theme_use=theme(legend.text = element_text(size=16), legend.title = element_text(size=20)) p_carDEC_denoised_hvg_1 = plot_cells(cds,color_cells_by = _batch,,graph_label_size=0,alpha=1,cell_size = 0.6)+ guides(colour = guide_legend(override.aes = list(alpha=0.7, size=5)))+ theme_use+ theme(legend.position = )

p_carDEC_denoised_hvg_2=plot_cells(cds,color_cells_by = ,label_branch_points=T,graph_label_size=2,alpha=1,cell_size = 0.6)+ theme(legend.position = , legend.title = element_text(vjust = 0.2), legend.text = element_text(angle=-50 ), legend.key.height = unit(0.5,), legend.key.width = unit(1,))+ guides(color = guide_colourbar(label.position = ))+theme_use

Cells aren't colored in a way that allows them to be grouped.

rr p_carDEC_denoised_hvg_3=ggplot(data=df_den)+geom_density(aes(x=Pseudotime,fill=dataset_batch),alpha=0.7)+ scale_y_continuous(expand = c(0,0))+ scale_x_continuous(expand = c(0,0))+ theme(legend.position=)+theme_use p_monocle_carDEC_denoised_hvg=egg::ggarrange(p_carDEC_denoised_hvg_1,p_carDEC_denoised_hvg_2,p_carDEC_denoised_hvg_3,ncol=3,draw=F)

rr p_monocle_carDEC_denoised_hvg

rr #cds_exprs=FetchData(obj0,vars = c(3A,100A8)) #df0=data.frame(cbind(pseudotime=pData(cds)\(Pseudotime,cds_exprs)) cds_exprs=as.matrix(SingleCellExperiment::counts(cds)[c(\FCGR3A\,\S100A8\),]) df0=data.frame(cbind(pseudotime=pData(cds)\)Pseudotime,log1p(t(cds_exprs)*mtx_sizefactor))) df0\(UMAP_1=reducedDims(cds)\)UMAP[,1] df0\(UMAP_2=reducedDims(cds)\)UMAP[,2] df0\(BatchID=pData(cds)\)dataset_batch df0=df0[is.finite(df0$pseudotime),] df0=df0[order(df0$pseudotime,decreasing = F),,drop=F] df0\(x=df0\)pseudotime/max(df0\(pseudotime) df_pseudotime_list\)carDEC_denoised_hvg=df0

  • Feature plots of FCGR3A and S100A8

rr p=get_plot4(df00 = df0)

rr p

rr df_den=colData(cds) tt1=ks.test(df_den\(Pseudotime[df_den\)dataset_batch==1],df_den\(Pseudotime[df_den\)dataset_batch==3]) tt1


    Two-sample Kolmogorov-Smirnov test

data:  df_den$Pseudotime[df_den$dataset_batch == \T1\] and df_den$Pseudotime[df_den$dataset_batch == \T3\]
D = 0.069253, p-value = 1.855e-06
alternative hypothesis: two-sided

rr tt2=ks.test(df_den\(Pseudotime[df_den\)dataset_batch==1],df_den\(Pseudotime[df_den\)dataset_batch==2]) tt2


    Two-sample Kolmogorov-Smirnov test

data:  df_den$Pseudotime[df_den$dataset_batch == \T1\] and df_den$Pseudotime[df_den$dataset_batch == \T2\]
D = 0.066806, p-value = 1.788e-08
alternative hypothesis: two-sided

rr tt3=ks.test(df_den\(Pseudotime[df_den\)dataset_batch==2],df_den\(Pseudotime[df_den\)dataset_batch==3]) tt3


    Two-sample Kolmogorov-Smirnov test

data:  df_den$Pseudotime[df_den$dataset_batch == \T2\] and df_den$Pseudotime[df_den$dataset_batch == \T3\]
D = 0.066796, p-value = 1.196e-06
alternative hypothesis: two-sided

rr Stable5[4,2:4]=matrix(get_p_new(c(tt1\(p.value,tt2\)p.value,tt3\(p.value),c(tt1\)statistic,tt2\(statistic,tt3\)statistic)),1,3)

3.3 All genes denoised

cds <- new_cell_data_set(mtx, cell_metadata = cell.meta.data,gene_metadata =gene_ann)
## Step 1: Normalize and pre-process the data
cds <- preprocess_cds(cds, num_dim = 32,method="PCA",norm_method="log",verbose = F)

## Step 2: Remove batch effects with cell alignment
##cds <- align_cds(cds, alignment_group = "BatchID", residual_model_formula_str = NULL)
## Step 3: Reduce the dimensions using UMAP
cds <- reduce_dimension(cds,reduction_method = "UMAP",preprocess_method="PCA",verbose = F)

## Step 4: Cluster the cells
cds <- cluster_cells(cds,reduction_method ="UMAP",cluster_method = "leiden",verbose = F)

# Construct the graph
# Note that, for the rest of the code to run, the graph should be fully (partionly) connected
## Step 5: Learn a graph
cds <- learn_graph(cds, use_partition = T,verbose = F)
colData(cds)$clusters=cds@clusters$UMAP$clusters
p1=plot_cells(cds,color_cells_by = "partition",label_cell_groups = F)+theme(legend.position = "top")
p2=plot_cells(cds,color_cells_by = "clusters",label_cell_groups=F,graph_label_size=2, label_leaves=F,label_branch_points=F)+theme(legend.position = "top")
p=cowplot::plot_grid(p1,p2,align = "h",ncol = 3)

rr p

rr ## Step 6: Order cells # root cells ids=get_earliest_principal_node(cds,cluster=c()) cds <- order_cells(cds, root_pr_nodes=ids) #plot_cells(cds,color_cells_by = )

rr colData(cds)\(pseudotime=pseudotime(cds) colData(cds)\)Pseudotime=colData(cds)\(pseudotime/max(colData(cds)\)pseudotime,na.rm = T) df_den=pData(cds)[,c(,_batch)] df_den=as.data.frame(df_den[!is.infinite(df_den$Pseudotime),]) set.seed(10) theme_use=theme(legend.text = element_text(size=16), legend.title = element_text(size=20)) p_carDEC_denoised_all_1=plot_cells(cds,color_cells_by = _batch,,graph_label_size=0,alpha=1,cell_size = 0.6)+ guides(colour = guide_legend(override.aes = list(alpha=0.7, size=5)))+ theme_use+ theme(legend.position = )

p_carDEC_denoised_all_2=plot_cells(cds,color_cells_by = ,label_branch_points=T,graph_label_size=2,alpha=1,cell_size = 0.6)+ theme(legend.position = , legend.title = element_text(vjust = 0.2), legend.text = element_text(angle=-50 ), legend.key.height = unit(0.5,), legend.key.width = unit(1,))+ guides(color = guide_colourbar(label.position = ))+theme_use

Cells aren't colored in a way that allows them to be grouped.

rr p_carDEC_denoised_all_3=ggplot(data=df_den)+geom_density(aes(x=Pseudotime,fill=dataset_batch),alpha=0.7)+ scale_y_continuous(expand = c(0,0))+ scale_x_continuous(expand = c(0,0))+ theme(legend.position=)+theme_use p_monocle_carDEC_denoised_all=egg::ggarrange(p_carDEC_denoised_all_1,p_carDEC_denoised_all_2,p_carDEC_denoised_all_3,ncol=3,draw=F)

rr p_monocle_carDEC_denoised_all

rr #cds_exprs=FetchData(obj0,vars = c(3A,100A8)) #df0=data.frame(cbind(pseudotime=pData(cds)\(Pseudotime,cds_exprs)) cds_exprs=as.matrix(SingleCellExperiment::counts(cds)[c(\FCGR3A\,\S100A8\),]) df0=data.frame(cbind(pseudotime=pData(cds)\)Pseudotime,log1p(t(cds_exprs)*mtx_sizefactor))) df0\(UMAP_1=reducedDims(cds)\)UMAP[,1] df0\(UMAP_2=reducedDims(cds)\)UMAP[,2] df0\(BatchID=pData(cds)\)dataset_batch df0=df0[is.finite(df0$pseudotime),] df0=df0[order(df0$pseudotime,decreasing = F),,drop=F] df0\(x=df0\)pseudotime/max(df0\(pseudotime) df_pseudotime_list\)carDEC_denoised_all=df0

  • Feature plots of FCGR3A and S100A8

rr p=get_plot4(df00 = df0)

rr p

rr df_den=colData(cds) tt1=ks.test(df_den\(Pseudotime[df_den\)dataset_batch==1],df_den\(Pseudotime[df_den\)dataset_batch==3]) tt1


    Two-sample Kolmogorov-Smirnov test

data:  df_den$Pseudotime[df_den$dataset_batch == \T1\] and df_den$Pseudotime[df_den$dataset_batch == \T3\]
D = 0.12681, p-value < 2.2e-16
alternative hypothesis: two-sided

rr tt2=ks.test(df_den\(Pseudotime[df_den\)dataset_batch==1],df_den\(Pseudotime[df_den\)dataset_batch==2]) tt2


    Two-sample Kolmogorov-Smirnov test

data:  df_den$Pseudotime[df_den$dataset_batch == \T1\] and df_den$Pseudotime[df_den$dataset_batch == \T2\]
D = 0.069599, p-value = 3.674e-09
alternative hypothesis: two-sided

rr tt3=ks.test(df_den\(Pseudotime[df_den\)dataset_batch==2],df_den\(Pseudotime[df_den\)dataset_batch==3]) tt3


    Two-sample Kolmogorov-Smirnov test

data:  df_den$Pseudotime[df_den$dataset_batch == \T2\] and df_den$Pseudotime[df_den$dataset_batch == \T3\]
D = 0.064936, p-value = 2.627e-06
alternative hypothesis: two-sided

rr Stable5[5,2:4]=matrix(get_p_new(c(tt1\(p.value,tt2\)p.value,tt3\(p.value),c(tt1\)statistic,tt2\(statistic,tt3\)statistic)),1,3)

4 Monocle3 using scVI

#adata=ad$read_h5ad("../final_processed_results/scVI Results/monocytes_ALL/adata_all.h5ad")
adata=ad$read_h5ad("../final_processed_results/scVI Results New/monocytes_ALL/adata_all.h5ad")
cell.meta.data=py_to_r(adata$obs)
cell.meta.data$dataset_batch=plyr::mapvalues(cell.meta.data$batch_label,names(maprules),maprules)
gene_ann0=py_to_r(adata$var)
gene_ann=data.frame(gene_short_name = make.unique(rownames(gene_ann0)),
                    row.names = make.unique(rownames(gene_ann0)))
mtx=t(py_to_r(adata$X))
colnames(mtx)=cell.meta.data$cellname
rownames(mtx)=rownames(gene_ann)
mtx_sizefactor=1e4/colSums(mtx)

4.1 Using latent

#mtx=mtx[gene_ann$VarianceType=="HVG",]
cds <- new_cell_data_set(mtx, cell_metadata = cell.meta.data,gene_metadata =gene_ann)
## Step 1: Normalize and pre-process the data
cds <- preprocess_cds(cds, num_dim = 32,method="PCA",norm_method="log",verbose = F)
tmp0=py_to_r(adata$obsm["X_latent"])
colnames(tmp0)=paste0("PC",1:ncol(tmp0))
reducedDims(cds)$PCA=tmp0

## Step 2: Remove batch effects with cell alignment
##cds <- align_cds(cds, alignment_group = "BatchID", residual_model_formula_str = NULL)
## Step 3: Reduce the dimensions using UMAP
cds <- reduce_dimension(cds,reduction_method = "UMAP",preprocess_method="PCA",verbose = F)

## Step 4: Cluster the cells
cds <- cluster_cells(cds,reduction_method ="UMAP",cluster_method = "leiden",verbose = F)

# Construct the graph
# Note that, for the rest of the code to run, the graph should be fully (partionly) connected
## Step 5: Learn a graph
cds <- learn_graph(cds, use_partition = T,verbose = F)
colData(cds)$clusters=cds@clusters$UMAP$clusters
p1=plot_cells(cds,color_cells_by = "partition",label_cell_groups = F)+theme(legend.position = "top")
p2=plot_cells(cds,color_cells_by = "clusters",label_cell_groups=F,graph_label_size=2, label_leaves=F,label_branch_points=F)+theme(legend.position = "top")
p=cowplot::plot_grid(p1,p2,align = "h",ncol = 3)
p

## Step 6: Order cells
# root cells
ids=get_earliest_principal_node(cds,cluster=c("3"))
cds <- order_cells(cds, root_pr_nodes=ids)
#plot_cells(cds,color_cells_by = "pseudotime")
colData(cds)$pseudotime=pseudotime(cds)
colData(cds)$Pseudotime=colData(cds)$pseudotime/max(colData(cds)$pseudotime,na.rm = T)
#saveRDS(cds,file = "cds_scvi.rds")
df_den=pData(cds)[,c("Pseudotime","dataset_batch")]
df_den=as.data.frame(df_den[!is.infinite(df_den$Pseudotime),])
set.seed(10)

theme_use=theme(legend.text = element_text(size=16),
                legend.title = element_text(size=20))

p_scVI_latent_all_1=plot_cells(cds,color_cells_by = "dataset_batch",,graph_label_size=0,alpha=1,cell_size = 0.6)+
  guides(colour = guide_legend(override.aes = list(alpha=0.7, size=5)))+
  theme_use+
  theme(legend.position = "top")
          
p_scVI_latent_all_2=plot_cells(cds,color_cells_by = "Pseudotime",label_branch_points=T,graph_label_size=2,alpha=1,cell_size = 0.6)+
            theme(legend.position = "top",
              legend.title = element_text(vjust = 0.2),
              legend.text = element_text(angle=-50 ),
                  legend.key.height = unit(0.5,"cm"),
                  legend.key.width = unit(1,"cm"))+
            guides(color = guide_colourbar(label.position = "top"))+theme_use

p_scVI_latent_all_3=ggplot(data=df_den)+geom_density(aes(x=Pseudotime,fill=dataset_batch),alpha=0.7)+
            scale_y_continuous(expand = c(0,0))+
            scale_x_continuous(expand = c(0,0))+
            theme(legend.position="top")+theme_use

p_monocle_scVI_latent_all=egg::ggarrange(p_scVI_latent_all_1,p_scVI_latent_all_2,p_scVI_latent_all_3,ncol=3,draw=F)
p_monocle_scVI_latent_all

#cds_exprs=FetchData(obj0,vars = c("FCGR3A","S100A8"))
#df0=data.frame(cbind(pseudotime=pData(cds)$Pseudotime,cds_exprs))
cds_exprs=as.matrix(SingleCellExperiment::counts(cds)[c("FCGR3A","S100A8"),])
#df0=data.frame(cbind(pseudotime=pData(cds)$Pseudotime,log1p(t(cds_exprs)*mtx_sizefactor)))
df0=data.frame(cbind(pseudotime=pData(cds)$Pseudotime,t(cds_exprs)))
df0$UMAP_1=reducedDims(cds)$UMAP[,1]
df0$UMAP_2=reducedDims(cds)$UMAP[,2]
df0$BatchID=pData(cds)$dataset_batch
df0=df0[is.finite(df0$pseudotime),]
df0=df0[order(df0$pseudotime,decreasing = F),,drop=F]
df0$x=df0$pseudotime/max(df0$pseudotime)
df_pseudotime_list$scVI_latent_all=df0
  • Feature plots of FCGR3A and S100A8
p=get_plot4(df00 = df0)
p

df_den=colData(cds)
tt1=ks.test(df_den$Pseudotime[df_den$dataset_batch=="T1"],df_den$Pseudotime[df_den$dataset_batch=="T3"])
tt1

    Two-sample Kolmogorov-Smirnov test

data:  df_den$Pseudotime[df_den$dataset_batch == "T1"] and df_den$Pseudotime[df_den$dataset_batch == "T3"]
D = 0.44217, p-value < 2.2e-16
alternative hypothesis: two-sided
tt2=ks.test(df_den$Pseudotime[df_den$dataset_batch=="T1"],df_den$Pseudotime[df_den$dataset_batch=="T2"])
tt2

    Two-sample Kolmogorov-Smirnov test

data:  df_den$Pseudotime[df_den$dataset_batch == "T1"] and df_den$Pseudotime[df_den$dataset_batch == "T2"]
D = 0.22787, p-value < 2.2e-16
alternative hypothesis: two-sided
tt3=ks.test(df_den$Pseudotime[df_den$dataset_batch=="T2"],df_den$Pseudotime[df_den$dataset_batch=="T3"])
tt3

    Two-sample Kolmogorov-Smirnov test

data:  df_den$Pseudotime[df_den$dataset_batch == "T2"] and df_den$Pseudotime[df_den$dataset_batch == "T3"]
D = 0.22133, p-value < 2.2e-16
alternative hypothesis: two-sided
Stable5[6,2:4]=matrix(get_p_new(c(tt1$p.value,tt2$p.value,tt3$p.value),c(tt1$statistic,tt2$statistic,tt3$statistic)),1,3)

4.2 HVGs denoised

cds <- new_cell_data_set(mtx[rownames(mtx)%in%hvg_genes$genename,], cell_metadata = cell.meta.data,gene_metadata =gene_ann[gene_ann$gene_short_name%in%hvg_genes$genename,,drop=F])
## Step 1: Normalize and pre-process the data
cds <- preprocess_cds(cds, num_dim = 32,method="PCA",norm_method="log",verbose = F)

## Step 2: Remove batch effects with cell alignment
##cds <- align_cds(cds, alignment_group = "BatchID", residual_model_formula_str = NULL)
## Step 3: Reduce the dimensions using UMAP
cds <- reduce_dimension(cds,reduction_method = "UMAP",preprocess_method="PCA",verbose = F)

## Step 4: Cluster the cells
cds <- cluster_cells(cds,reduction_method ="UMAP",cluster_method = "leiden",verbose = F)

# Construct the graph
# Note that, for the rest of the code to run, the graph should be fully (partionly) connected
## Step 5: Learn a graph
cds <- learn_graph(cds, use_partition = T,verbose = F)
colData(cds)$clusters=cds@clusters$UMAP$clusters
p1=plot_cells(cds,color_cells_by = "partition",label_cell_groups = F)+theme(legend.position = "top")
p2=plot_cells(cds,color_cells_by = "clusters",label_cell_groups=F,graph_label_size=2, label_leaves=F,label_branch_points=F)+theme(legend.position = "top")
p=cowplot::plot_grid(p1,p2,align = "h",ncol = 3)
p

## Step 6: Order cells
# root cells
ids=get_earliest_principal_node(cds,cluster=c("3"))
cds <- order_cells(cds, root_pr_nodes=ids)
#plot_cells(cds,color_cells_by = "pseudotime")
colData(cds)$pseudotime=pseudotime(cds)
colData(cds)$Pseudotime=colData(cds)$pseudotime/max(colData(cds)$pseudotime,na.rm = T)
df_den=pData(cds)[,c("Pseudotime","dataset_batch")]
df_den=as.data.frame(df_den[!is.infinite(df_den$Pseudotime),])
set.seed(10)
theme_use=theme(legend.text = element_text(size=16),
                legend.title = element_text(size=20))
p_scvi_denoised_hvg_1=plot_cells(cds,color_cells_by = "dataset_batch",,graph_label_size=0,alpha=1,cell_size = 0.6)+
  guides(colour = guide_legend(override.aes = list(alpha=0.7, size=5)))+
  theme_use+
  theme(legend.position = "top")
          
p_scvi_denoised_hvg_2=plot_cells(cds,color_cells_by = "Pseudotime",label_branch_points=T,graph_label_size=2,alpha=1,cell_size = 0.6)+
            theme(legend.position = "top",
              legend.title = element_text(vjust = 0.2),
              legend.text = element_text(angle=-50 ),
                  legend.key.height = unit(0.5,"cm"),
                  legend.key.width = unit(1,"cm"))+
            guides(color = guide_colourbar(label.position = "top"))+theme_use
Cells aren't colored in a way that allows them to be grouped.
p_scvi_denoised_hvg_3=ggplot(data=df_den)+geom_density(aes(x=Pseudotime,fill=dataset_batch),alpha=0.7)+
            scale_y_continuous(expand = c(0,0))+
            scale_x_continuous(expand = c(0,0))+
            theme(legend.position="top")+theme_use
p_monocle_scvi_denoised_hvg=egg::ggarrange(p_scvi_denoised_hvg_1,p_scvi_denoised_hvg_2,p_scvi_denoised_hvg_3,ncol=3,draw=F)
p_monocle_scvi_denoised_hvg

#cds_exprs=FetchData(obj0,vars = c("FCGR3A","S100A8"))
#df0=data.frame(cbind(pseudotime=pData(cds)$Pseudotime,cds_exprs))
cds_exprs=as.matrix(SingleCellExperiment::counts(cds)[c("FCGR3A","S100A8"),])
#df0=data.frame(cbind(pseudotime=pData(cds)$Pseudotime,log1p(t(cds_exprs)*mtx_sizefactor)))
df0=data.frame(cbind(pseudotime=pData(cds)$Pseudotime,t(cds_exprs)))
df0$UMAP_1=reducedDims(cds)$UMAP[,1]
df0$UMAP_2=reducedDims(cds)$UMAP[,2]
df0$BatchID=pData(cds)$dataset_batch
df0=df0[is.finite(df0$pseudotime),]
df0=df0[order(df0$pseudotime,decreasing = F),,drop=F]
df0$x=df0$pseudotime/max(df0$pseudotime)
df_pseudotime_list$scVI_denosied_hvg=df0
  • Feature plots of FCGR3A and S100A8
p=get_plot4(df00 = df0)
p

df_den=colData(cds)
tt1=ks.test(df_den$Pseudotime[df_den$dataset_batch=="T1"],df_den$Pseudotime[df_den$dataset_batch=="T3"])
tt1

    Two-sample Kolmogorov-Smirnov test

data:  df_den$Pseudotime[df_den$dataset_batch == "T1"] and df_den$Pseudotime[df_den$dataset_batch == "T3"]
D = 0.516, p-value < 2.2e-16
alternative hypothesis: two-sided
tt2=ks.test(df_den$Pseudotime[df_den$dataset_batch=="T1"],df_den$Pseudotime[df_den$dataset_batch=="T2"])
tt2

    Two-sample Kolmogorov-Smirnov test

data:  df_den$Pseudotime[df_den$dataset_batch == "T1"] and df_den$Pseudotime[df_den$dataset_batch == "T2"]
D = 0.3063, p-value < 2.2e-16
alternative hypothesis: two-sided
tt3=ks.test(df_den$Pseudotime[df_den$dataset_batch=="T2"],df_den$Pseudotime[df_den$dataset_batch=="T3"])
tt3

    Two-sample Kolmogorov-Smirnov test

data:  df_den$Pseudotime[df_den$dataset_batch == "T2"] and df_den$Pseudotime[df_den$dataset_batch == "T3"]
D = 0.22798, p-value < 2.2e-16
alternative hypothesis: two-sided
Stable5[7,2:4]=matrix(get_p_new(c(tt1$p.value,tt2$p.value,tt3$p.value),c(tt1$statistic,tt2$statistic,tt3$statistic)),1,3)

4.3 All genes denoised

cds <- new_cell_data_set(mtx, cell_metadata = cell.meta.data,gene_metadata =gene_ann)
## Step 1: Normalize and pre-process the data
cds <- preprocess_cds(cds, num_dim = 32,method="PCA",norm_method="log",verbose = F)

## Step 2: Remove batch effects with cell alignment
##cds <- align_cds(cds, alignment_group = "BatchID", residual_model_formula_str = NULL)
## Step 3: Reduce the dimensions using UMAP
cds <- reduce_dimension(cds,reduction_method = "UMAP",preprocess_method="PCA",verbose = F)

## Step 4: Cluster the cells
cds <- cluster_cells(cds,reduction_method ="UMAP",cluster_method = "leiden",verbose = F)

# Construct the graph
# Note that, for the rest of the code to run, the graph should be fully (partionly) connected
## Step 5: Learn a graph
cds <- learn_graph(cds, use_partition = T,verbose = F)
colData(cds)$clusters=cds@clusters$UMAP$clusters
p1=plot_cells(cds,color_cells_by = "partition",label_cell_groups = F)+theme(legend.position = "top")
p2=plot_cells(cds,color_cells_by = "clusters",label_cell_groups=F,graph_label_size=2, label_leaves=F,label_branch_points=F)+theme(legend.position = "top")
p=cowplot::plot_grid(p1,p2,align = "h",ncol = 3)
p

## Step 6: Order cells
# root cells
ids=get_earliest_principal_node(cds,cluster=c("3"))
cds <- order_cells(cds, root_pr_nodes=ids)
#plot_cells(cds,color_cells_by = "pseudotime")
x0=pseudotime(cds)
x0[is.infinite(x0)]=NA
colData(cds)$pseudotime=x0

colData(cds)$Pseudotime=colData(cds)$pseudotime/max(colData(cds)$pseudotime,na.rm = T)
df_den=pData(cds)[,c("Pseudotime","dataset_batch")]
df_den=as.data.frame(df_den[!is.infinite(df_den$Pseudotime),])
set.seed(10)

theme_use=theme(legend.text = element_text(size=16),
                legend.title = element_text(size=20))

p_scVI_denoised_all_1=plot_cells(cds,color_cells_by = "dataset_batch",,graph_label_size=0,alpha=1,cell_size = 0.6)+
  guides(colour = guide_legend(override.aes = list(alpha=0.7, size=5)))+
  theme_use+
  theme(legend.position = "top")
          
p_scVI_denoised_all_2=plot_cells(cds,color_cells_by = "Pseudotime",label_branch_points=T,graph_label_size=2,alpha=1,cell_size = 0.6)+
            theme(legend.position = "top",
              legend.title = element_text(vjust = 0.2),
              legend.text = element_text(angle=-50 ),
                  legend.key.height = unit(0.5,"cm"),
                  legend.key.width = unit(1,"cm"))+
            guides(color = guide_colourbar(label.position = "top"))+theme_use

p_scVI_denoised_all_3=ggplot(data=df_den)+geom_density(aes(x=Pseudotime,fill=dataset_batch),alpha=0.7)+
            scale_y_continuous(expand = c(0,0))+
            scale_x_continuous(expand = c(0,0))+
            theme(legend.position="top")+theme_use

p_monocle_scVI_denoised_all=egg::ggarrange(p_scVI_denoised_all_1,p_scVI_denoised_all_2,p_scVI_denoised_all_3,ncol=3,draw=F)
p_monocle_scVI_denoised_all

#cds_exprs=FetchData(obj0,vars = c("FCGR3A","S100A8"))
#df0=data.frame(cbind(pseudotime=pData(cds)$Pseudotime,cds_exprs))
cds_exprs=as.matrix(SingleCellExperiment::counts(cds)[c("FCGR3A","S100A8"),])
#df0=data.frame(cbind(pseudotime=pData(cds)$Pseudotime,log1p(t(cds_exprs)*mtx_sizefactor)))
df0=data.frame(cbind(pseudotime=pData(cds)$Pseudotime,t(cds_exprs)))
df0$UMAP_1=reducedDims(cds)$UMAP[,1]
df0$UMAP_2=reducedDims(cds)$UMAP[,2]
df0$BatchID=pData(cds)$dataset_batch
df0=df0[is.finite(df0$pseudotime),]
df0=df0[order(df0$pseudotime,decreasing = F),,drop=F]
df0$x=df0$pseudotime/max(df0$pseudotime)
df_pseudotime_list$scVI_denosied_all=df0
  • Feature plots of FCGR3A and S100A8
p=get_plot4(df00 = df0)
p

df_den=colData(cds)
tt1=ks.test(df_den$Pseudotime[df_den$dataset_batch=="T1"],df_den$Pseudotime[df_den$dataset_batch=="T3"])
tt1

    Two-sample Kolmogorov-Smirnov test

data:  df_den$Pseudotime[df_den$dataset_batch == "T1"] and df_den$Pseudotime[df_den$dataset_batch == "T3"]
D = 0.52707, p-value < 2.2e-16
alternative hypothesis: two-sided
tt2=ks.test(df_den$Pseudotime[df_den$dataset_batch=="T1"],df_den$Pseudotime[df_den$dataset_batch=="T2"])
p-value will be approximate in the presence of ties
tt2

    Two-sample Kolmogorov-Smirnov test

data:  df_den$Pseudotime[df_den$dataset_batch == "T1"] and df_den$Pseudotime[df_den$dataset_batch == "T2"]
D = 0.31699, p-value < 2.2e-16
alternative hypothesis: two-sided
tt3=ks.test(df_den$Pseudotime[df_den$dataset_batch=="T2"],df_den$Pseudotime[df_den$dataset_batch=="T3"])
p-value will be approximate in the presence of ties
tt3

    Two-sample Kolmogorov-Smirnov test

data:  df_den$Pseudotime[df_den$dataset_batch == "T2"] and df_den$Pseudotime[df_den$dataset_batch == "T3"]
D = 0.26217, p-value < 2.2e-16
alternative hypothesis: two-sided
Stable5[8,2:4]=matrix(get_p_new(c(tt1$p.value,tt2$p.value,tt3$p.value),c(tt1$statistic,tt2$statistic,tt3$statistic)),1,3)

5 Monocle3 using dca+combat

#adata=ad$read_h5ad("../final_processed_results/dca Results/adata_all.h5ad")
adata=ad$read_h5ad("../final_processed_results/dca Results New/adata_all.h5ad")
cell.meta.data=py_to_r(adata$obs)
cell.meta.data$dataset_batch=plyr::mapvalues(cell.meta.data$batch_label,names(maprules),maprules)
gene_ann0=py_to_r(adata$var)
gene_ann=data.frame(gene_short_name = make.unique(rownames(gene_ann0)),
                    row.names = make.unique(rownames(gene_ann0)))
mtx=t(py_to_r(adata$X))
colnames(mtx)=cell.meta.data$cellname
rownames(mtx)=rownames(gene_ann)
mtx_sizefactor=1e4/colSums(mtx)

5.1 Using combated latent from dca

#mtx=mtx[gene_ann$VarianceType=="HVG",]
cds <- new_cell_data_set(mtx, cell_metadata = cell.meta.data,gene_metadata =gene_ann)
## Step 1: Normalize and pre-process the data
cds <- preprocess_cds(cds, num_dim = 32,method="PCA",norm_method="log")

tmp0=py_to_r(adata$obsm["X_dca_latent"]) #original dca
colnames(tmp0)=paste0("PC",1:ncol(tmp0))
reducedDims(cds)$PCA=tmp0

## Step 2: Remove batch effects with cell alignment
##cds <- align_cds(cds, alignment_group = "BatchID", residual_model_formula_str = NULL)
## Step 3: Reduce the dimensions using UMAP
cds <- reduce_dimension(cds,reduction_method = "UMAP",preprocess_method="PCA")

## Step 4: Cluster the cells
cds <- cluster_cells(cds,reduction_method ="UMAP",cluster_method = "leiden")

# Construct the graph
# Note that, for the rest of the code to run, the graph should be fully (partionly) connected
## Step 5: Learn a graph
cds <- learn_graph(cds, use_partition = T,verbose = F)
colData(cds)$clusters=cds@clusters$UMAP$clusters
p1=plot_cells(cds,color_cells_by = "partition",label_cell_groups = F)+theme(legend.position = "top")
p2=plot_cells(cds,color_cells_by = "clusters",label_cell_groups=F,graph_label_size=2, label_leaves=F,label_branch_points=F)+theme(legend.position = "top")
p=cowplot::plot_grid(p1,p2,align = "h",ncol = 3)
p

## Step 6: Order cells
# root cells
ids=get_earliest_principal_node(cds,cluster=c("4"))
cds <- order_cells(cds, root_pr_nodes=ids)
#plot_cells(cds,color_cells_by = "pseudotime")
colData(cds)$pseudotime=pseudotime(cds)
colData(cds)$Pseudotime=colData(cds)$pseudotime/max(colData(cds)$pseudotime,na.rm = T)
#saveRDS(cds,file="cds_dca.rds")
df_den=pData(cds)[,c("Pseudotime","dataset_batch")]
df_den=as.data.frame(df_den[!is.infinite(df_den$Pseudotime),])
set.seed(10)

theme_use=theme(legend.text = element_text(size=16),
                legend.title = element_text(size=20))

p_dca_latent_all_1=plot_cells(cds,color_cells_by = "dataset_batch",,graph_label_size=0,alpha=1,cell_size = 0.6)+
  guides(colour = guide_legend(override.aes = list(alpha=0.7, size=5)))+
  theme_use+
  theme(legend.position = "top")
          
p_dca_latent_all_2=plot_cells(cds,color_cells_by = "Pseudotime",label_branch_points=T,graph_label_size=2,alpha=1,cell_size = 0.6)+
            theme(legend.position = "top",
              legend.title = element_text(vjust = 0.2),
              legend.text = element_text(angle=-50 ),
                  legend.key.height = unit(0.5,"cm"),
                  legend.key.width = unit(1,"cm"))+
            guides(color = guide_colourbar(label.position = "top"))+theme_use

p_dca_latent_all_3=ggplot(data=df_den)+geom_density(aes(x=Pseudotime,fill=dataset_batch),alpha=0.7)+
            scale_y_continuous(expand = c(0,0))+
            scale_x_continuous(expand = c(0,0))+
            theme(legend.position="top")+theme_use

p_monocle_dca_latent_all=egg::ggarrange(p_dca_latent_all_1,p_dca_latent_all_2,p_dca_latent_all_3,ncol=3,draw=F)
p_monocle_dca_latent_all

#cds_exprs=FetchData(obj0,vars = c("FCGR3A","S100A8"))
#df0=data.frame(cbind(pseudotime=pData(cds)$Pseudotime,cds_exprs))
cds_exprs=as.matrix(SingleCellExperiment::counts(cds)[c("FCGR3A","S100A8"),])
#df0=data.frame(cbind(pseudotime=pData(cds)$Pseudotime,log1p(t(cds_exprs)*mtx_sizefactor)))
df0=data.frame(cbind(pseudotime=pData(cds)$Pseudotime,t(cds_exprs)))
df0$UMAP_1=reducedDims(cds)$UMAP[,1]
df0$UMAP_2=reducedDims(cds)$UMAP[,2]
df0$BatchID=pData(cds)$dataset_batch
df0=df0[is.finite(df0$pseudotime),]
df0=df0[order(df0$pseudotime,decreasing = F),,drop=F]
df0$x=df0$pseudotime/max(df0$pseudotime)
df_pseudotime_list$dca_latent_all=df0
  • Feature plots of FCGR3A and S100A8
p=get_plot4(df00 = df0)
p

df_den=colData(cds)
tt1=ks.test(df_den$Pseudotime[df_den$dataset_batch=="T1"],df_den$Pseudotime[df_den$dataset_batch=="T3"])
p-value will be approximate in the presence of ties
tt1

    Two-sample Kolmogorov-Smirnov test

data:  df_den$Pseudotime[df_den$dataset_batch == "T1"] and df_den$Pseudotime[df_den$dataset_batch == "T3"]
D = 0.12069, p-value < 2.2e-16
alternative hypothesis: two-sided
tt2=ks.test(df_den$Pseudotime[df_den$dataset_batch=="T1"],df_den$Pseudotime[df_den$dataset_batch=="T2"])
p-value will be approximate in the presence of ties
tt2

    Two-sample Kolmogorov-Smirnov test

data:  df_den$Pseudotime[df_den$dataset_batch == "T1"] and df_den$Pseudotime[df_den$dataset_batch == "T2"]
D = 0.088498, p-value = 1.499e-14
alternative hypothesis: two-sided
tt3=ks.test(df_den$Pseudotime[df_den$dataset_batch=="T2"],df_den$Pseudotime[df_den$dataset_batch=="T3"])
tt3

    Two-sample Kolmogorov-Smirnov test

data:  df_den$Pseudotime[df_den$dataset_batch == "T2"] and df_den$Pseudotime[df_den$dataset_batch == "T3"]
D = 0.14218, p-value < 2.2e-16
alternative hypothesis: two-sided
Stable5[9,2:4]=matrix(get_p_new(c(tt1$p.value,tt2$p.value,tt3$p.value),c(tt1$statistic,tt2$statistic,tt3$statistic)),1,3)

5.2 HVGs denoised

cds <- new_cell_data_set(mtx[rownames(mtx)%in%hvg_genes$genename,], cell_metadata = cell.meta.data,gene_metadata =gene_ann[gene_ann$gene_short_name%in%hvg_genes$genename,,drop=F])
## Step 1: Normalize and pre-process the data
cds <- preprocess_cds(cds, num_dim = 32,method="PCA",norm_method="log",verbose = F)

tmp0=py_to_r(adata$obsm["X_pcahvg"]) #original dca
colnames(tmp0)=paste0("PC",1:ncol(tmp0))
reducedDims(cds)$PCA=tmp0


## Step 2: Remove batch effects with cell alignment
##cds <- align_cds(cds, alignment_group = "BatchID", residual_model_formula_str = NULL)
## Step 3: Reduce the dimensions using UMAP
cds <- reduce_dimension(cds,reduction_method = "UMAP",preprocess_method="PCA",verbose = F)

## Step 4: Cluster the cells
cds <- cluster_cells(cds,reduction_method ="UMAP",cluster_method = "leiden",verbose = F)

# Construct the graph
# Note that, for the rest of the code to run, the graph should be fully (partionly) connected
## Step 5: Learn a graph
cds <- learn_graph(cds, use_partition = T,verbose = F)
colData(cds)$clusters=cds@clusters$UMAP$clusters
p1=plot_cells(cds,color_cells_by = "partition",label_cell_groups = F)+theme(legend.position = "top")
p2=plot_cells(cds,color_cells_by = "clusters",label_cell_groups=F,graph_label_size=2, label_leaves=F,label_branch_points=F)+theme(legend.position = "top")
p=cowplot::plot_grid(p1,p2,align = "h",ncol = 3)
p

## Step 6: Order cells
# root cells
ids=get_earliest_principal_node(cds,cluster=c("1","3","4"))
cds <- order_cells(cds, root_pr_nodes=ids)
#plot_cells(cds,color_cells_by = "pseudotime")
colData(cds)$pseudotime=pseudotime(cds)
colData(cds)$Pseudotime=colData(cds)$pseudotime/max(colData(cds)$pseudotime,na.rm = T)
df_den=pData(cds)[,c("Pseudotime","dataset_batch")]
df_den=as.data.frame(df_den[!is.infinite(df_den$Pseudotime),])
set.seed(10)

theme_use=theme(legend.text = element_text(size=16),
                legend.title = element_text(size=20))

p_dca_denoised_hvg_1=plot_cells(cds,color_cells_by = "dataset_batch",,graph_label_size=0,alpha=1,cell_size = 0.6)+
  guides(colour = guide_legend(override.aes = list(alpha=0.7, size=5)))+
  theme_use+
  theme(legend.position = "top")
          
p_dca_denoised_hvg_2=plot_cells(cds,color_cells_by = "Pseudotime",label_branch_points=T,graph_label_size=2,alpha=1,cell_size = 0.6)+
            theme(legend.position = "top",
              legend.title = element_text(vjust = 0.2),
              legend.text = element_text(angle=-50 ),
                  legend.key.height = unit(0.5,"cm"),
                  legend.key.width = unit(1,"cm"))+
            guides(color = guide_colourbar(label.position = "top"))+theme_use

p_dca_denoised_hvg_3=ggplot(data=df_den)+geom_density(aes(x=Pseudotime,fill=dataset_batch),alpha=0.7)+
            scale_y_continuous(expand = c(0,0))+
            scale_x_continuous(expand = c(0,0))+
            theme(legend.position="top")+theme_use

p_monocle_dca_denoised_hvg=egg::ggarrange(p_dca_denoised_hvg_1,p_dca_denoised_hvg_2,p_dca_denoised_hvg_3,ncol=3,draw=F)
p_monocle_dca_denoised_hvg

#cds_exprs=FetchData(obj0,vars = c("FCGR3A","S100A8"))
#df0=data.frame(cbind(pseudotime=pData(cds)$Pseudotime,cds_exprs))
cds_exprs=as.matrix(SingleCellExperiment::counts(cds)[c("FCGR3A","S100A8"),])
df0=data.frame(cbind(pseudotime=pData(cds)$Pseudotime,t(cds_exprs)))
df0$UMAP_1=reducedDims(cds)$UMAP[,1]
df0$UMAP_2=reducedDims(cds)$UMAP[,2]
df0$BatchID=pData(cds)$dataset_batch
df0=df0[is.finite(df0$pseudotime),]
df0=df0[order(df0$pseudotime,decreasing = F),,drop=F]
df0$x=df0$pseudotime/max(df0$pseudotime)
df_pseudotime_list$dca_denoised_hvg=df0
  • Feature plots of FCGR3A and S100A8
p=get_plot4(df00 = df0)
p

df_den=colData(cds)
tt1=ks.test(df_den$Pseudotime[df_den$dataset_batch=="T1"],df_den$Pseudotime[df_den$dataset_batch=="T3"])
p-value will be approximate in the presence of ties
tt1

    Two-sample Kolmogorov-Smirnov test

data:  df_den$Pseudotime[df_den$dataset_batch == "T1"] and df_den$Pseudotime[df_den$dataset_batch == "T3"]
D = 0.48635, p-value < 2.2e-16
alternative hypothesis: two-sided
tt2=ks.test(df_den$Pseudotime[df_den$dataset_batch=="T1"],df_den$Pseudotime[df_den$dataset_batch=="T2"])
tt2

    Two-sample Kolmogorov-Smirnov test

data:  df_den$Pseudotime[df_den$dataset_batch == "T1"] and df_den$Pseudotime[df_den$dataset_batch == "T2"]
D = 0.099731, p-value < 2.2e-16
alternative hypothesis: two-sided
tt3=ks.test(df_den$Pseudotime[df_den$dataset_batch=="T2"],df_den$Pseudotime[df_den$dataset_batch=="T3"])
p-value will be approximate in the presence of ties
tt3

    Two-sample Kolmogorov-Smirnov test

data:  df_den$Pseudotime[df_den$dataset_batch == "T2"] and df_den$Pseudotime[df_den$dataset_batch == "T3"]
D = 0.50313, p-value < 2.2e-16
alternative hypothesis: two-sided
Stable5[10,2:4]=matrix(get_p_new(c(tt1$p.value,tt2$p.value,tt3$p.value),c(tt1$statistic,tt2$statistic,tt3$statistic)),1,3)

5.3 All genes denoised

cds <- new_cell_data_set(mtx, cell_metadata = cell.meta.data,gene_metadata =gene_ann)
## Step 1: Normalize and pre-process the data
cds <- preprocess_cds(cds, num_dim = 32,method="PCA",norm_method="log",verbose = F)

## Step 2: Remove batch effects with cell alignment
##cds <- align_cds(cds, alignment_group = "BatchID", residual_model_formula_str = NULL)
## Step 3: Reduce the dimensions using UMAP
cds <- reduce_dimension(cds,reduction_method = "UMAP",preprocess_method="PCA",verbose = F)

tmp0=py_to_r(adata$obsm["X_pcaall"]) #original dca
colnames(tmp0)=paste0("PC",1:ncol(tmp0))
reducedDims(cds)$PCA=tmp0


## Step 4: Cluster the cells
cds <- cluster_cells(cds,reduction_method ="UMAP",cluster_method = "leiden",verbose = F)

# Construct the graph
# Note that, for the rest of the code to run, the graph should be fully (partionly) connected
## Step 5: Learn a graph
cds <- learn_graph(cds, use_partition = T,verbose = F)
colData(cds)$clusters=cds@clusters$UMAP$clusters
p1=plot_cells(cds,color_cells_by = "partition",label_cell_groups = F)+theme(legend.position = "top")
p2=plot_cells(cds,color_cells_by = "clusters",label_cell_groups=F,graph_label_size=2, label_leaves=F,label_branch_points=F)+theme(legend.position = "top")
p=cowplot::plot_grid(p1,p2,align = "h",ncol = 3)
p

## Step 6: Order cells
# root cells
ids=get_earliest_principal_node(cds,cluster=c("2","4","5"))
cds <- order_cells(cds, root_pr_nodes=ids)
#plot_cells(cds,color_cells_by = "pseudotime")
colData(cds)$pseudotime=pseudotime(cds)
colData(cds)$Pseudotime=colData(cds)$pseudotime/max(colData(cds)$pseudotime,na.rm = T)
df_den=pData(cds)[,c("Pseudotime","dataset_batch")]
df_den=as.data.frame(df_den[!is.infinite(df_den$Pseudotime),])
set.seed(10)

theme_use=theme(legend.text = element_text(size=16),
                legend.title = element_text(size=20))

p_dca_denoised_all_1=plot_cells(cds,color_cells_by = "dataset_batch",,graph_label_size=0,alpha=1,cell_size = 0.6)+
  guides(colour = guide_legend(override.aes = list(alpha=0.7, size=5)))+
  theme_use+
  theme(legend.position = "top")
          
p_dca_denoised_all_2=plot_cells(cds,color_cells_by = "Pseudotime",label_branch_points=T,graph_label_size=2,alpha=1,cell_size = 0.6)+
            theme(legend.position = "top",
              legend.title = element_text(vjust = 0.2),
              legend.text = element_text(angle=-50 ),
                  legend.key.height = unit(0.5,"cm"),
                  legend.key.width = unit(1,"cm"))+
            guides(color = guide_colourbar(label.position = "top"))+theme_use

p_dca_denoised_all_3=ggplot(data=df_den)+geom_density(aes(x=Pseudotime,fill=dataset_batch),alpha=0.7)+
            scale_y_continuous(expand = c(0,0))+
            scale_x_continuous(expand = c(0,0))+
            theme(legend.position="top")+theme_use

p_monocle_dca_denoised_all=egg::ggarrange(p_dca_denoised_all_1,p_dca_denoised_all_2,p_dca_denoised_all_3,ncol=3,draw=F)
p_monocle_dca_denoised_all

#cds_exprs=FetchData(obj0,vars = c("FCGR3A","S100A8"))
#df0=data.frame(cbind(pseudotime=pData(cds)$Pseudotime,cds_exprs))
cds_exprs=as.matrix(SingleCellExperiment::counts(cds)[c("FCGR3A","S100A8"),])
#df0=data.frame(cbind(pseudotime=pData(cds)$Pseudotime,log1p(t(cds_exprs)*mtx_sizefactor)))
df0=data.frame(cbind(pseudotime=pData(cds)$Pseudotime,t(cds_exprs)))
df0$UMAP_1=reducedDims(cds)$UMAP[,1]
df0$UMAP_2=reducedDims(cds)$UMAP[,2]
df0$BatchID=pData(cds)$dataset_batch
df0=df0[is.finite(df0$pseudotime),]
df0=df0[order(df0$pseudotime,decreasing = F),,drop=F]
df0$x=df0$pseudotime/max(df0$pseudotime)
df_pseudotime_list$dca_denoised_all=df0
  • Feature plots of FCGR3A and S100A8
p=get_plot4(df00 = df0)
p

df_den=colData(cds)
tt1=ks.test(df_den$Pseudotime[df_den$dataset_batch=="T1"],df_den$Pseudotime[df_den$dataset_batch=="T3"])
p-value will be approximate in the presence of ties
tt1

    Two-sample Kolmogorov-Smirnov test

data:  df_den$Pseudotime[df_den$dataset_batch == "T1"] and df_den$Pseudotime[df_den$dataset_batch == "T3"]
D = 0.92747, p-value < 2.2e-16
alternative hypothesis: two-sided
tt2=ks.test(df_den$Pseudotime[df_den$dataset_batch=="T1"],df_den$Pseudotime[df_den$dataset_batch=="T2"])
p-value will be approximate in the presence of ties
tt2

    Two-sample Kolmogorov-Smirnov test

data:  df_den$Pseudotime[df_den$dataset_batch == "T1"] and df_den$Pseudotime[df_den$dataset_batch == "T2"]
D = 0.14265, p-value < 2.2e-16
alternative hypothesis: two-sided
tt3=ks.test(df_den$Pseudotime[df_den$dataset_batch=="T2"],df_den$Pseudotime[df_den$dataset_batch=="T3"])
p-value will be approximate in the presence of ties
tt3

    Two-sample Kolmogorov-Smirnov test

data:  df_den$Pseudotime[df_den$dataset_batch == "T2"] and df_den$Pseudotime[df_den$dataset_batch == "T3"]
D = 0.87006, p-value < 2.2e-16
alternative hypothesis: two-sided
Stable5[11,2:4]=matrix(get_p_new(c(tt1$p.value,tt2$p.value,tt3$p.value),c(tt1$statistic,tt2$statistic,tt3$statistic)),1,3)

6 Monocle3 using MNN

output=readRDS("../final_processed_results/MNN_corrected_all.rds")
mtx=output@assays$data$corrected
cell.meta.data=colData(output)
cell.meta.data$dataset_batch=plyr::mapvalues(cell.meta.data$batch_label,names(maprules),maprules)
gene_ann=data.frame(gene_short_name = make.unique(rownames(mtx)),
                    row.names = make.unique(rownames(mtx)))

6.0.1 HVGs denoised

#mtx=mtx[gene_ann$VarianceType=="HVG",]
cds <- new_cell_data_set(mtx[rownames(mtx)%in%hvg_genes$genename,], 
                         cell_metadata = cell.meta.data,
                         gene_metadata =gene_ann[gene_ann$gene_short_name%in%hvg_genes$genename,,drop=F])
## Step
## Step 1: Normalize and pre-process the data
cds <- preprocess_cds(cds, num_dim = 32,method="PCA",norm_method="log")
#tmp0=py_to_r(adata$obsm["X_dca_latent"])
#colnames(tmp0)=paste0("PC",1:ncol(tmp0))
#reducedDims(cds)$PCA=tmp0

## Step 2: Remove batch effects with cell alignment
##cds <- align_cds(cds, alignment_group = "BatchID", residual_model_formula_str = NULL)
## Step 3: Reduce the dimensions using UMAP
cds <- reduce_dimension(cds,reduction_method = "UMAP",preprocess_method="PCA")

## Step 4: Cluster the cells
cds <- cluster_cells(cds,reduction_method ="UMAP",cluster_method = "leiden")

# Construct the graph
# Note that, for the rest of the code to run, the graph should be fully (partionly) connected
## Step 5: Learn a graph
cds <- learn_graph(cds, use_partition = T,verbose = F)
colData(cds)$clusters=cds@clusters$UMAP$clusters
p1=plot_cells(cds,color_cells_by = "partition",label_cell_groups = F)+theme(legend.position = "top")
p2=plot_cells(cds,color_cells_by = "clusters",label_cell_groups=F,graph_label_size=2, label_leaves=F,label_branch_points=F)+theme(legend.position = "top")
p=cowplot::plot_grid(p1,p2,align = "h",ncol = 3)
p

## Step 6: Order cells
# root cells
ids=get_earliest_principal_node(cds,cluster=c("2","3","4"))
cds <- order_cells(cds, root_pr_nodes=ids)
#plot_cells(cds,color_cells_by = "pseudotime")
colData(cds)$pseudotime=pseudotime(cds)
colData(cds)$Pseudotime=colData(cds)$pseudotime/max(colData(cds)$pseudotime,na.rm = T)
#saveRDS(cds,file="cds_mnn.rds")
df_den=pData(cds)[,c("Pseudotime","dataset_batch")]
df_den=as.data.frame(df_den[!is.infinite(df_den$Pseudotime),])
set.seed(10)

theme_use=theme(legend.text = element_text(size=16),
                legend.title = element_text(size=20))

p_mnn_denoised_hvg_1=plot_cells(cds,color_cells_by = "dataset_batch",,graph_label_size=0,alpha=1,cell_size = 0.6)+
  guides(colour = guide_legend(override.aes = list(alpha=0.7, size=5)))+
  theme_use+
  theme(legend.position = "top")
          
p_mnn_denoised_hvg_2=plot_cells(cds,color_cells_by = "Pseudotime",label_branch_points=T,graph_label_size=2,alpha=1,cell_size = 0.6)+
            theme(legend.position = "top",
              legend.title = element_text(vjust = 0.2),
              legend.text = element_text(angle=-50 ),
                  legend.key.height = unit(0.5,"cm"),
                  legend.key.width = unit(1,"cm"))+
            guides(color = guide_colourbar(label.position = "top"))+theme_use

p_mnn_denoised_hvg_3=ggplot(data=df_den)+geom_density(aes(x=Pseudotime,fill=dataset_batch),alpha=0.7)+
            scale_y_continuous(expand = c(0,0))+
            scale_x_continuous(expand = c(0,0))+
            theme(legend.position="top")+theme_use

p_monocle_mnn_denoised_hvg=egg::ggarrange(p_mnn_denoised_hvg_1,p_mnn_denoised_hvg_2,p_mnn_denoised_hvg_3,ncol=3,draw=F)
p_monocle_mnn_denoised_hvg

#cds_exprs=FetchData(obj0,vars = c("FCGR3A","S100A8"))
#df0=data.frame(cbind(pseudotime=pData(cds)$Pseudotime,cds_exprs))
cds_exprs=as.matrix(SingleCellExperiment::counts(cds)[c("FCGR3A","S100A8"),])
df0=data.frame(cbind(pseudotime=pData(cds)$Pseudotime,t(cds_exprs)*mtx_sizefactor))
df0$UMAP_1=reducedDims(cds)$UMAP[,1]
df0$UMAP_2=reducedDims(cds)$UMAP[,2]
df0$BatchID=pData(cds)$dataset_batch
df0=df0[is.finite(df0$pseudotime),]
df0=df0[order(df0$pseudotime,decreasing = F),,drop=F]
df0$x=df0$pseudotime/max(df0$pseudotime)
df_pseudotime_list$mnn_denoised_hvg=df0
  • Feature plots of FCGR3A and S100A8
p=get_plot4(df00 = df0)
p

df_den=colData(cds)
tt1=ks.test(df_den$Pseudotime[df_den$dataset_batch=="T1"],df_den$Pseudotime[df_den$dataset_batch=="T3"])
p-value will be approximate in the presence of ties
tt1

    Two-sample Kolmogorov-Smirnov test

data:  df_den$Pseudotime[df_den$dataset_batch == "T1"] and df_den$Pseudotime[df_den$dataset_batch == "T3"]
D = 0.43599, p-value < 2.2e-16
alternative hypothesis: two-sided
tt2=ks.test(df_den$Pseudotime[df_den$dataset_batch=="T1"],df_den$Pseudotime[df_den$dataset_batch=="T2"])
p-value will be approximate in the presence of ties
tt2

    Two-sample Kolmogorov-Smirnov test

data:  df_den$Pseudotime[df_den$dataset_batch == "T1"] and df_den$Pseudotime[df_den$dataset_batch == "T2"]
D = 0.73449, p-value < 2.2e-16
alternative hypothesis: two-sided
tt3=ks.test(df_den$Pseudotime[df_den$dataset_batch=="T2"],df_den$Pseudotime[df_den$dataset_batch=="T3"])
p-value will be approximate in the presence of ties
tt3

    Two-sample Kolmogorov-Smirnov test

data:  df_den$Pseudotime[df_den$dataset_batch == "T2"] and df_den$Pseudotime[df_den$dataset_batch == "T3"]
D = 0.86706, p-value < 2.2e-16
alternative hypothesis: two-sided
Stable5[12,2:4]=matrix(get_p_new(c(tt1$p.value,tt2$p.value,tt3$p.value),c(tt1$statistic,tt2$statistic,tt3$statistic)),1,3)

6.0.2 All genes denoised

output=readRDS("../final_processed_results/MNN_corrected_all.rds")
mtx=output@assays$data$corrected
cell.meta.data=colData(output)
cell.meta.data$dataset_batch=plyr::mapvalues(cell.meta.data$batch_label,names(maprules),maprules)
gene_ann=data.frame(gene_short_name = make.unique(rownames(mtx)),
                    row.names = make.unique(rownames(mtx)))
#colnames(mtx)=colData(output)$cellname
#rownames(mtx)=rownames(gene_ann)
#mtx_sizefactor=1e4/colSums(mtx)
#mtx=mtx[gene_ann$VarianceType=="HVG",]
cds <- new_cell_data_set(mtx, cell_metadata = cell.meta.data,gene_metadata =gene_ann)
## Step 1: Normalize and pre-process the data
cds <- preprocess_cds(cds, num_dim = 32,method="PCA",norm_method="log")
#tmp0=py_to_r(adata$obsm["X_dca_latent"])
#colnames(tmp0)=paste0("PC",1:ncol(tmp0))
#reducedDims(cds)$PCA=tmp0

## Step 2: Remove batch effects with cell alignment
##cds <- align_cds(cds, alignment_group = "BatchID", residual_model_formula_str = NULL)
## Step 3: Reduce the dimensions using UMAP
cds <- reduce_dimension(cds,reduction_method = "UMAP",preprocess_method="PCA")

## Step 4: Cluster the cells
cds <- cluster_cells(cds,reduction_method ="UMAP",cluster_method = "leiden")

# Construct the graph
# Note that, for the rest of the code to run, the graph should be fully (partionly) connected
## Step 5: Learn a graph
cds <- learn_graph(cds, use_partition = T,verbose = F)
colData(cds)$clusters=cds@clusters$UMAP$clusters
p1=plot_cells(cds,color_cells_by = "partition",label_cell_groups = F)+theme(legend.position = "top")
p2=plot_cells(cds,color_cells_by = "clusters",label_cell_groups=F,graph_label_size=2, label_leaves=F,label_branch_points=F)+theme(legend.position = "top")
p=cowplot::plot_grid(p1,p2,align = "h",ncol = 3)
p

## Step 6: Order cells
# root cells
ids=get_earliest_principal_node(cds,cluster=c("6","3","5"))
cds <- order_cells(cds, root_pr_nodes=ids)
#plot_cells(cds,color_cells_by = "pseudotime")
colData(cds)$pseudotime=pseudotime(cds)
colData(cds)$Pseudotime=colData(cds)$pseudotime/max(colData(cds)$pseudotime,na.rm = T)
df_den=pData(cds)[,c("Pseudotime","dataset_batch")]
df_den=as.data.frame(df_den[!is.infinite(df_den$Pseudotime),])
set.seed(10)

theme_use=theme(legend.text = element_text(size=16),
                legend.title = element_text(size=20))

p_mnn_denoised_all_1=plot_cells(cds,color_cells_by = "dataset_batch",,graph_label_size=0,alpha=1,cell_size = 0.6)+
  guides(colour = guide_legend(override.aes = list(alpha=0.7, size=5)))+
  theme_use+
  theme(legend.position = "top")
          
p_mnn_denoised_all_2=plot_cells(cds,color_cells_by = "Pseudotime",label_branch_points=T,graph_label_size=2,alpha=1,cell_size = 0.6)+
            theme(legend.position = "top",
              legend.title = element_text(vjust = 0.2),
              legend.text = element_text(angle=-50 ),
                  legend.key.height = unit(0.5,"cm"),
                  legend.key.width = unit(1,"cm"))+
            guides(color = guide_colourbar(label.position = "top"))+theme_use

p_mnn_denoised_all_3=ggplot(data=df_den)+geom_density(aes(x=Pseudotime,fill=dataset_batch),alpha=0.7)+
            scale_y_continuous(expand = c(0,0))+
            scale_x_continuous(expand = c(0,0))+
            theme(legend.position="top")+theme_use

p_monocle_mnn_denoised_all=egg::ggarrange(p_mnn_denoised_all_1,p_mnn_denoised_all_2,p_mnn_denoised_all_3,ncol=3,draw=F)
p_monocle_mnn_denoised_all

#cds_exprs=FetchData(obj0,vars = c("FCGR3A","S100A8"))
#df0=data.frame(cbind(pseudotime=pData(cds)$Pseudotime,cds_exprs))
cds_exprs=as.matrix(SingleCellExperiment::counts(cds)[c("FCGR3A","S100A8"),])
df0=data.frame(cbind(pseudotime=pData(cds)$Pseudotime,t(cds_exprs)*mtx_sizefactor))
df0$UMAP_1=reducedDims(cds)$UMAP[,1]
df0$UMAP_2=reducedDims(cds)$UMAP[,2]
df0$BatchID=pData(cds)$dataset_batch
df0=df0[is.finite(df0$pseudotime),]
df0=df0[order(df0$pseudotime,decreasing = F),,drop=F]
df0$x=df0$pseudotime/max(df0$pseudotime)
df_pseudotime_list$mnn_denoised_all=df0
  • Feature plots of FCGR3A and S100A8
p=get_plot4(df00 = df0)
p

df_den=colData(cds)
tt1=ks.test(df_den$Pseudotime[df_den$dataset_batch=="T1"],df_den$Pseudotime[df_den$dataset_batch=="T3"])
p-value will be approximate in the presence of ties
tt1

    Two-sample Kolmogorov-Smirnov test

data:  df_den$Pseudotime[df_den$dataset_batch == "T1"] and df_den$Pseudotime[df_den$dataset_batch == "T3"]
D = 0.37703, p-value < 2.2e-16
alternative hypothesis: two-sided
tt2=ks.test(df_den$Pseudotime[df_den$dataset_batch=="T1"],df_den$Pseudotime[df_den$dataset_batch=="T2"])
p-value will be approximate in the presence of ties
tt2

    Two-sample Kolmogorov-Smirnov test

data:  df_den$Pseudotime[df_den$dataset_batch == "T1"] and df_den$Pseudotime[df_den$dataset_batch == "T2"]
D = 0.55184, p-value < 2.2e-16
alternative hypothesis: two-sided
tt3=ks.test(df_den$Pseudotime[df_den$dataset_batch=="T2"],df_den$Pseudotime[df_den$dataset_batch=="T3"])
p-value will be approximate in the presence of ties
tt3

    Two-sample Kolmogorov-Smirnov test

data:  df_den$Pseudotime[df_den$dataset_batch == "T2"] and df_den$Pseudotime[df_den$dataset_batch == "T3"]
D = 0.53852, p-value < 2.2e-16
alternative hypothesis: two-sided
Stable5[13,2:4]=matrix(get_p_new(c(tt1$p.value,tt2$p.value,tt3$p.value),c(tt1$statistic,tt2$statistic,tt3$statistic)),1,3)

7 Monocle3 using scanorama

adata=ad$read_h5ad("../final_processed_results/scanorama Results/adata_ALL.h5ad")#
cell.meta.data=py_to_r(adata$obs)
cell.meta.data$dataset_batch=plyr::mapvalues(cell.meta.data$batch_label,names(maprules),maprules)
gene_ann0=py_to_r(adata$raw$var)
gene_ann=data.frame(gene_short_name = make.unique(rownames(gene_ann0)),
                    row.names = make.unique(rownames(gene_ann0)))
mtx=t(py_to_r(adata$X$tocsc()))#adata$raw
colnames(mtx)=cell.meta.data$cellname
rownames(mtx)=rownames(gene_ann)
mtx_sizefactor=1e4/colSums(mtx)

7.1 Using latent

#mtx=mtx[gene_ann$VarianceType=="HVG",]
cds <- new_cell_data_set(mtx, cell_metadata = cell.meta.data,gene_metadata =gene_ann)
## Step 1: Normalize and pre-process the data
cds <- preprocess_cds(cds, num_dim = 50,method="PCA",norm_method="log")

tmp0=py_to_r(adata$obsm["X_scanorama"])
colnames(tmp0)=paste0("PC",1:ncol(tmp0))
reducedDims(cds)$PCA=tmp0

## Step 2: Remove batch effects with cell alignment
##cds <- align_cds(cds, alignment_group = "BatchID", residual_model_formula_str = NULL)
## Step 3: Reduce the dimensions using UMAP
cds <- reduce_dimension(cds,reduction_method = "UMAP",preprocess_method="PCA")

## Step 4: Cluster the cells
cds <- cluster_cells(cds,reduction_method ="UMAP",cluster_method = "leiden")

# Construct the graph
# Note that, for the rest of the code to run, the graph should be fully (partionly) connected
## Step 5: Learn a graph
cds <- learn_graph(cds, use_partition = T,verbose = F)
colData(cds)$clusters=cds@clusters$UMAP$clusters
p1=plot_cells(cds,color_cells_by = "partition",label_cell_groups = F)+theme(legend.position = "top")
p2=plot_cells(cds,color_cells_by = "clusters",label_cell_groups=F,graph_label_size=2, label_leaves=F,label_branch_points=F)+theme(legend.position = "top")
p=cowplot::plot_grid(p1,p2,align = "h",ncol = 3)
p

## Step 6: Order cells
# root cells
ids=get_earliest_principal_node(cds,cluster=c("2"))#need to specify
cds <- order_cells(cds, root_pr_nodes=ids)
#plot_cells(cds,color_cells_by = "pseudotime")
colData(cds)$pseudotime=pseudotime(cds)
colData(cds)$Pseudotime=colData(cds)$pseudotime/max(colData(cds)$pseudotime,na.rm = T)
#saveRDS(cds,file="cds_scanorama.rds")
df_den=pData(cds)[,c("Pseudotime","dataset_batch")]
df_den=as.data.frame(df_den[!is.infinite(df_den$Pseudotime),])
set.seed(10)
theme_use=theme(legend.text = element_text(size=16),
                legend.title = element_text(size=20))
p_monocle_scanorama_latent_hvg_1=plot_cells(cds,color_cells_by = "dataset_batch",,graph_label_size=0,alpha=1,cell_size = 0.6)+
  guides(colour = guide_legend(override.aes = list(alpha=0.7, size=5)))+
  theme_use+
  theme(legend.position = "top")
          
p_monocle_scanorama_latent_hvg_2=plot_cells(cds,color_cells_by = "Pseudotime",label_branch_points=T,graph_label_size=2,alpha=1,cell_size = 0.6)+
            theme(legend.position = "top",
              legend.title = element_text(vjust = 0.2),
              legend.text = element_text(angle=-50 ),
                  legend.key.height = unit(0.5,"cm"),
                  legend.key.width = unit(1,"cm"))+
            guides(color = guide_colourbar(label.position = "top"))+theme_use
Cells aren't colored in a way that allows them to be grouped.
p_monocle_scanorama_latent_hvg_3=ggplot(data=df_den)+geom_density(aes(x=Pseudotime,fill=dataset_batch),alpha=0.7)+
            scale_y_continuous(expand = c(0,0))+
            scale_x_continuous(expand = c(0,0))+
            theme(legend.position="top")+theme_use
p_monocle_scanorama_latent_hvg=egg::ggarrange(p_monocle_scanorama_latent_hvg_1,p_monocle_scanorama_latent_hvg_2,p_monocle_scanorama_latent_hvg_3,ncol=3,draw=F)
p_monocle_scanorama_latent_hvg

#cds_exprs=FetchData(obj0,vars = c("FCGR3A","S100A8"))
#df0=data.frame(cbind(pseudotime=pData(cds)$Pseudotime,cds_exprs))
cds_exprs=as.matrix(SingleCellExperiment::counts(cds)[c("FCGR3A","S100A8"),])
df0=data.frame(cbind(pseudotime=pData(cds)$Pseudotime,t(cds_exprs)))
df0$UMAP_1=reducedDims(cds)$UMAP[,1]
df0$UMAP_2=reducedDims(cds)$UMAP[,2]
df0$BatchID=pData(cds)$dataset_batch
df0=df0[is.finite(df0$pseudotime),]
df0=df0[order(df0$pseudotime,decreasing = F),,drop=F]
df0$x=df0$pseudotime/max(df0$pseudotime)
df_pseudotime_list$scanorama_latent_hvg=df0
  • Feature plots of FCGR3A and S100A8
p=get_plot4(df00 = df0)
p

df_den=colData(cds)
tt1=ks.test(df_den$Pseudotime[df_den$dataset_batch=="T1"],df_den$Pseudotime[df_den$dataset_batch=="T3"])
p-value will be approximate in the presence of ties
tt1

    Two-sample Kolmogorov-Smirnov test

data:  df_den$Pseudotime[df_den$dataset_batch == "T1"] and df_den$Pseudotime[df_den$dataset_batch == "T3"]
D = 0.18479, p-value < 2.2e-16
alternative hypothesis: two-sided
tt2=ks.test(df_den$Pseudotime[df_den$dataset_batch=="T1"],df_den$Pseudotime[df_den$dataset_batch=="T2"])
p-value will be approximate in the presence of ties
tt2

    Two-sample Kolmogorov-Smirnov test

data:  df_den$Pseudotime[df_den$dataset_batch == "T1"] and df_den$Pseudotime[df_den$dataset_batch == "T2"]
D = 0.34817, p-value < 2.2e-16
alternative hypothesis: two-sided
tt3=ks.test(df_den$Pseudotime[df_den$dataset_batch=="T2"],df_den$Pseudotime[df_den$dataset_batch=="T3"])
tt3

    Two-sample Kolmogorov-Smirnov test

data:  df_den$Pseudotime[df_den$dataset_batch == "T2"] and df_den$Pseudotime[df_den$dataset_batch == "T3"]
D = 0.19376, p-value < 2.2e-16
alternative hypothesis: two-sided
Stable5[14,2:4]=matrix(get_p_new(c(tt1$p.value,tt2$p.value,tt3$p.value),c(tt1$statistic,tt2$statistic,tt3$statistic)),1,3)

7.2 HVGs denoised

#cds <- new_cell_data_set(mtx[rownames(mtx)%in%hvg_genes$genename,], cell_metadata = cell.meta.data,gene_metadata =gene_ann[gene_ann$gene_short_name%in%hvg_genes$genename,,drop=F])
cds <- new_cell_data_set(mtx, cell_metadata = cell.meta.data,gene_metadata =gene_ann)
## Step 1: Normalize and pre-process the data
cds <- preprocess_cds(cds, num_dim = 50,method="PCA",norm_method="log",verbose = F)
tmp0=py_to_r(adata$obsm["X_hvgpca"])
colnames(tmp0)=paste0("PC",1:ncol(tmp0))
reducedDims(cds)$PCA=tmp0
## Step 2: Remove batch effects with cell alignment
##cds <- align_cds(cds, alignment_group = "BatchID", residual_model_formula_str = NULL)
## Step 3: Reduce the dimensions using UMAP
cds <- reduce_dimension(cds,reduction_method = "UMAP",preprocess_method="PCA",verbose = F)
## Step 4: Cluster the cells
cds <- cluster_cells(cds,reduction_method ="UMAP",cluster_method = "leiden",verbose = F)
# Construct the graph
# Note that, for the rest of the code to run, the graph should be fully (partionly) connected
## Step 5: Learn a graph
cds <- learn_graph(cds, use_partition = T,verbose = F)

  |                                                                                                                          
  |                                                                                                                    |   0%
  |                                                                                                                          
  |====================================================================================================================| 100%
colData(cds)$clusters=cds@clusters$UMAP$clusters
p1=plot_cells(cds,color_cells_by = "partition",label_cell_groups = F)+theme(legend.position = "top")
p2=plot_cells(cds,color_cells_by = "clusters",label_cell_groups=F,graph_label_size=2, label_leaves=F,label_branch_points=F)+theme(legend.position = "top")
p=cowplot::plot_grid(p1,p2,align = "h",ncol = 3)
p

## Step 6: Order cells
# root cells
ids=get_earliest_principal_node(cds,cluster=c("2"))
cds <- order_cells(cds, root_pr_nodes=ids)
#plot_cells(cds,color_cells_by = "pseudotime")
colData(cds)$pseudotime=pseudotime(cds)
colData(cds)$Pseudotime=colData(cds)$pseudotime/max(colData(cds)$pseudotime,na.rm = T)
df_den=pData(cds)[,c("Pseudotime","dataset_batch")]
df_den=as.data.frame(df_den[!is.infinite(df_den$Pseudotime),])
set.seed(10)
theme_use=theme(legend.text = element_text(size=16),
                legend.title = element_text(size=20))
p_monocle_scanorama_denoised_hvg_1=plot_cells(cds,color_cells_by = "dataset_batch",,graph_label_size=0,alpha=1,cell_size = 0.6)+
  guides(colour = guide_legend(override.aes = list(alpha=0.7, size=5)))+
  theme_use+
  theme(legend.position = "top")
          
p_monocle_scanorama_denoised_hvg_2=plot_cells(cds,color_cells_by = "Pseudotime",label_branch_points=T,graph_label_size=2,alpha=1,cell_size = 0.6)+
            theme(legend.position = "top",
              legend.title = element_text(vjust = 0.2),
              legend.text = element_text(angle=-50 ),
                  legend.key.height = unit(0.5,"cm"),
                  legend.key.width = unit(1,"cm"))+
            guides(color = guide_colourbar(label.position = "top"))+theme_use
Cells aren't colored in a way that allows them to be grouped.
p_monocle_scanorama_denoised_hvg_3=ggplot(data=df_den)+geom_density(aes(x=Pseudotime,fill=dataset_batch),alpha=0.7)+
            scale_y_continuous(expand = c(0,0))+
            scale_x_continuous(expand = c(0,0))+
            theme(legend.position="top")+theme_use
p_monocle_scanorama_denoised_hvg=egg::ggarrange(p_monocle_scanorama_denoised_hvg_1,p_monocle_scanorama_denoised_hvg_2,p_monocle_scanorama_denoised_hvg_3,ncol=3,draw=F)
p_monocle_scanorama_denoised_hvg

#cds_exprs=FetchData(obj0,vars = c("FCGR3A","S100A8"))
#df0=data.frame(cbind(pseudotime=pData(cds)$Pseudotime,cds_exprs))
cds_exprs=as.matrix(SingleCellExperiment::counts(cds)[c("FCGR3A","S100A8"),])
df0=data.frame(cbind(pseudotime=pData(cds)$Pseudotime,t(cds_exprs)*mtx_sizefactor))
df0$UMAP_1=reducedDims(cds)$UMAP[,1]
df0$UMAP_2=reducedDims(cds)$UMAP[,2]
df0$BatchID=pData(cds)$dataset_batch
df0=df0[is.finite(df0$pseudotime),]
df0=df0[order(df0$pseudotime,decreasing = F),,drop=F]
df0$x=df0$pseudotime/max(df0$pseudotime)
df_pseudotime_list$scanorama_denoised_hvg=df0
  • Feature plots of FCGR3A and S100A8
p=get_plot4(df00 = df0)
p

df_den=colData(cds)
tt1=ks.test(df_den$Pseudotime[df_den$dataset_batch=="T1"],df_den$Pseudotime[df_den$dataset_batch=="T3"])
tt1

    Two-sample Kolmogorov-Smirnov test

data:  df_den$Pseudotime[df_den$dataset_batch == "T1"] and df_den$Pseudotime[df_den$dataset_batch == "T3"]
D = 0.18717, p-value < 2.2e-16
alternative hypothesis: two-sided
tt2=ks.test(df_den$Pseudotime[df_den$dataset_batch=="T1"],df_den$Pseudotime[df_den$dataset_batch=="T2"])
tt2

    Two-sample Kolmogorov-Smirnov test

data:  df_den$Pseudotime[df_den$dataset_batch == "T1"] and df_den$Pseudotime[df_den$dataset_batch == "T2"]
D = 0.30887, p-value < 2.2e-16
alternative hypothesis: two-sided
tt3=ks.test(df_den$Pseudotime[df_den$dataset_batch=="T2"],df_den$Pseudotime[df_den$dataset_batch=="T3"])
tt3

    Two-sample Kolmogorov-Smirnov test

data:  df_den$Pseudotime[df_den$dataset_batch == "T2"] and df_den$Pseudotime[df_den$dataset_batch == "T3"]
D = 0.49383, p-value < 2.2e-16
alternative hypothesis: two-sided
Stable5[15,2:4]=matrix(get_p_new(c(tt1$p.value,tt2$p.value,tt3$p.value),c(tt1$statistic,tt2$statistic,tt3$statistic)),1,3)

7.3 All genes denoised

#cds <- new_cell_data_set(mtx[rownames(mtx)%in%hvg_genes$genename,], cell_metadata = cell.meta.data,gene_metadata =gene_ann[gene_ann$gene_short_name%in%hvg_genes$genename,,drop=F])
cds <- new_cell_data_set(mtx, cell_metadata = cell.meta.data,gene_metadata =gene_ann)
## Step 1: Normalize and pre-process the data
cds <- preprocess_cds(cds, num_dim = 30,method="PCA",norm_method="log",verbose = F)

tmp0=py_to_r(adata$obsm["X_pca"])
colnames(tmp0)=paste0("PC",1:ncol(tmp0))
reducedDims(cds)$PCA=tmp0[,1:30]

## Step 2: Remove batch effects with cell alignment
##cds <- align_cds(cds, alignment_group = "BatchID", residual_model_formula_str = NULL)
## Step 3: Reduce the dimensions using UMAP
cds <- reduce_dimension(cds,reduction_method = "UMAP",preprocess_method="PCA",verbose = F)

## Step 4: Cluster the cells
cds <- cluster_cells(cds,reduction_method ="UMAP",cluster_method = "leiden",verbose = F)

# Construct the graph
# Note that, for the rest of the code to run, the graph should be fully (partionly) connected
## Step 5: Learn a graph
cds <- learn_graph(cds, use_partition = T,verbose = F)
colData(cds)$clusters=cds@clusters$UMAP$clusters
p1=plot_cells(cds,color_cells_by = "partition",label_cell_groups = F)+theme(legend.position = "top")
p2=plot_cells(cds,color_cells_by = "clusters",label_cell_groups=F,graph_label_size=2, label_leaves=F,label_branch_points=F)+theme(legend.position = "top")
p=cowplot::plot_grid(p1,p2,align = "h",ncol = 3)
p

## Step 6: Order cells
# root cells
ids=get_earliest_principal_node(cds,cluster=c("1"))
cds <- order_cells(cds, root_pr_nodes=ids)
#plot_cells(cds,color_cells_by = "pseudotime")
colData(cds)$pseudotime=pseudotime(cds)
colData(cds)$Pseudotime=colData(cds)$pseudotime/max(colData(cds)$pseudotime,na.rm = T)
df_den=pData(cds)[,c("Pseudotime","dataset_batch")]
df_den=as.data.frame(df_den[!is.infinite(df_den$Pseudotime),])
set.seed(10)
theme_use=theme(legend.text = element_text(size=16),
                legend.title = element_text(size=20))
p_monocle_scanorama_denoised_all_1=plot_cells(cds,color_cells_by = "dataset_batch",,graph_label_size=0,alpha=1,cell_size = 0.6)+
  guides(colour = guide_legend(override.aes = list(alpha=0.7, size=5)))+
  theme_use+
  theme(legend.position = "top")
          
p_monocle_scanorama_denoised_all_2=plot_cells(cds,color_cells_by = "Pseudotime",label_branch_points=T,graph_label_size=2,alpha=1,cell_size = 0.6)+
            theme(legend.position = "top",
              legend.title = element_text(vjust = 0.2),
              legend.text = element_text(angle=-50 ),
                  legend.key.height = unit(0.5,"cm"),
                  legend.key.width = unit(1,"cm"))+
            guides(color = guide_colourbar(label.position = "top"))+theme_use
Cells aren't colored in a way that allows them to be grouped.
p_monocle_scanorama_denoised_all_3=ggplot(data=df_den)+geom_density(aes(x=Pseudotime,fill=dataset_batch),alpha=0.7)+
            scale_y_continuous(expand = c(0,0))+
            scale_x_continuous(expand = c(0,0))+
            theme(legend.position="top")+theme_use
p_monocle_scanorama_denoised_all=egg::ggarrange(p_monocle_scanorama_denoised_all_1,p_monocle_scanorama_denoised_all_2,p_monocle_scanorama_denoised_all_3,ncol=3,draw=F)
p_monocle_scanorama_denoised_all

#cds_exprs=FetchData(obj0,vars = c("FCGR3A","S100A8"))
#df0=data.frame(cbind(pseudotime=pData(cds)$Pseudotime,cds_exprs))
cds_exprs=as.matrix(SingleCellExperiment::counts(cds)[c("FCGR3A","S100A8"),])
df0=data.frame(cbind(pseudotime=pData(cds)$Pseudotime,t(cds_exprs)*mtx_sizefactor))
df0$UMAP_1=reducedDims(cds)$UMAP[,1]
df0$UMAP_2=reducedDims(cds)$UMAP[,2]
df0$BatchID=pData(cds)$dataset_batch
df0=df0[is.finite(df0$pseudotime),]
df0=df0[order(df0$pseudotime,decreasing = F),,drop=F]
df0$x=df0$pseudotime/max(df0$pseudotime)
df_pseudotime_list$scanorama_denoised_all=df0
  • Feature plots of FCGR3A and S100A8
p=get_plot4(df00 = df0)
p

df_den=colData(cds)
tt1=ks.test(df_den$Pseudotime[df_den$dataset_batch=="T1"],df_den$Pseudotime[df_den$dataset_batch=="T3"])
p-value will be approximate in the presence of ties
tt1

    Two-sample Kolmogorov-Smirnov test

data:  df_den$Pseudotime[df_den$dataset_batch == "T1"] and df_den$Pseudotime[df_den$dataset_batch == "T3"]
D = 0.14931, p-value < 2.2e-16
alternative hypothesis: two-sided
tt2=ks.test(df_den$Pseudotime[df_den$dataset_batch=="T1"],df_den$Pseudotime[df_den$dataset_batch=="T2"])
p-value will be approximate in the presence of ties
tt2

    Two-sample Kolmogorov-Smirnov test

data:  df_den$Pseudotime[df_den$dataset_batch == "T1"] and df_den$Pseudotime[df_den$dataset_batch == "T2"]
D = 0.39706, p-value < 2.2e-16
alternative hypothesis: two-sided
tt3=ks.test(df_den$Pseudotime[df_den$dataset_batch=="T2"],df_den$Pseudotime[df_den$dataset_batch=="T3"])
tt3

    Two-sample Kolmogorov-Smirnov test

data:  df_den$Pseudotime[df_den$dataset_batch == "T2"] and df_den$Pseudotime[df_den$dataset_batch == "T3"]
D = 0.29988, p-value < 2.2e-16
alternative hypothesis: two-sided
Stable5[16,2:4]=matrix(get_p_new(c(tt1$p.value,tt2$p.value,tt3$p.value),c(tt1$statistic,tt2$statistic,tt3$statistic)),1,3)
suppressPackageStartupMessages(library(cowplot))
#Supplementary Table 5
write.table(Stable5,file="KS_table.csv",sep=",")
openxlsx::write.xlsx(Stable5,file="KS_table.xlsx")
Stable5 %>%
  kable() %>%
  kable_styling()
Method T1.v.s..T2 T1.v.s..T3 T2.v.s..T3
Raw count HVGs Raw count HVGs 0.572 (<2.2e-16) 0.461 (<2.2e-16) 0.709 (<2.2e-16)
Raw count All Raw count All 0.925 (<2.2e-16) 0.684 (<2.2e-16) 0.775 (<2.2e-16)
CarDEC (latent) CarDEC (latent) 0.052 (7.98e-04) 0.034 (1.84e-02) 0.052 (2.92e-04)
CarDEC (denoised HVGs) CarDEC (denoised HVGs) 0.069 (1.85e-06) 0.067 (1.79e-08) 0.067 (1.2e-06)
CarDEC (denoised All) CarDEC (denoised All) 0.127 (<2.2e-16) 0.07 (3.67e-09) 0.065 (2.63e-06)
scVI (latent) scVI (latent) 0.442 (<2.2e-16) 0.228 (<2.2e-16) 0.221 (<2.2e-16)
scVI (denoised HVGs) scVI (denoised HVGs) 0.516 (<2.2e-16) 0.306 (<2.2e-16) 0.228 (<2.2e-16)
scVI (denoised All) scVI (denoised All) 0.527 (<2.2e-16) 0.317 (<2.2e-16) 0.262 (<2.2e-16)
DCA (latent) DCA (latent) 0.121 (<2.2e-16) 0.088 (1.5e-14) 0.142 (<2.2e-16)
DCA (denoised HVGs) DCA (denoised HVGs) 0.486 (<2.2e-16) 0.1 (<2.2e-16) 0.503 (<2.2e-16)
DCA (denoised All) DCA (denoised All) 0.927 (<2.2e-16) 0.143 (<2.2e-16) 0.87 (<2.2e-16)
MNN (denoised HVGs) MNN (denoised HVGs) 0.436 (<2.2e-16) 0.734 (<2.2e-16) 0.867 (<2.2e-16)
MNN (denoised All) MNN (denoised All) 0.377 (<2.2e-16) 0.552 (<2.2e-16) 0.539 (<2.2e-16)
Scanorama (latent) Scanorama (latent) 0.185 (<2.2e-16) 0.348 (<2.2e-16) 0.194 (<2.2e-16)
Scanorama (denoised HVGs) Scanorama (denoised HVGs) 0.187 (<2.2e-16) 0.309 (<2.2e-16) 0.494 (<2.2e-16)
Scanorama (denoised All) Scanorama (denoised All) 0.149 (<2.2e-16) 0.397 (<2.2e-16) 0.3 (<2.2e-16)

8 Figures

8.1 Main Figure (Figure 5)

fig_width=30
fig_height=25
labels=letters[1:5]
Methods=c("Raw count HVGs","Raw count All","CarDEC (latent)","CarDEC (denoised HVGs)","CarDEC (denoised All)","scVI (latent)","scVI (denoised HVGs)","scVI (denoised All)","DCA (latent)","DCA (denoised HVGs)","DCA (denoised All)","MNN (denoised HVGs)","MNN (denoised All)","Scanorama (latent)","Scanorama (denoised HVGs)","Scanorama (denoised All)")
use_id=c(4,15,10,7,12)
get_draw_plot=function(plot_id=1,plist0){
  x=0.02
  y=1-plot_id/5
  width=0.98
  height=1/5-0.01 # total number of figures is 12
  pp=draw_plot(egg::ggarrange(plots=plist0,nrow = 1,draw = F,newpage = F),x = x,y = y,width = width,height = height)
  #draw_label(labels[plot_id],x=x,y=y+1/6,hjust =1,vjust = 0.5,size = 35)
  return(pp)
}
get_label_pos=function(plot_id=1){
  x=0
  y=1-plot_id/5
  #draw_label(labels[plot_id],x=x,y=y+1/6,hjust =1,vjust = 0.5,size = 35)
  return(c(x,y+1/5-1/30))
}
get_title_pos=function(plot_id=1){
  x=0.015
  y=1-plot_id/5
  #draw_label(labels[plot_id],x=x,y=y+1/6,hjust =1,vjust = 0.5,size = 35)
  return(c(x,y+1/10-1/60))
}
get_plot_list=function(x,y){
  x0=rep(list(),length=length(x)+length(y))
  x0[1:length(x)]=x[1:3]
  x0[(length(x)+1):length(x0)]=y[1:2]
  return(x0)
}
p=ggdraw()+get_draw_plot(1,get_plot_list(list(p_carDEC_denoised_hvg_1+scale_color_brewer(name="dataset_batch",palette = "Set2"),
                                              p_carDEC_denoised_hvg_2,
                                              p_carDEC_denoised_hvg_3+scale_fill_brewer(name="dataset_batch",palette = "Set2")),
                                         get_plot4_sep(df_pseudotime_list[[4]])[c(3,4)]))+
get_draw_plot(2,get_plot_list(list(p_monocle_scanorama_denoised_hvg_1+scale_color_brewer(name="dataset_batch",palette = "Set2"),
                                   p_monocle_scanorama_denoised_hvg_2,
                                   p_monocle_scanorama_denoised_hvg_3+scale_fill_brewer(name="dataset_batch",palette = "Set2")),
                              get_plot4_sep(df_pseudotime_list[[15]])[c(3,4)]))+
  get_draw_plot(3,get_plot_list(list(p_dca_denoised_hvg_1+scale_color_brewer(name="dataset_batch",palette = "Set2"),
                                     p_dca_denoised_hvg_2,
                                     p_dca_denoised_hvg_3+scale_fill_brewer(name="dataset_batch",palette = "Set2")), 
                                get_plot4_sep(df_pseudotime_list[[10]])[c(3,4)]))+
  get_draw_plot(4,get_plot_list(list(p_scvi_denoised_hvg_1+scale_color_brewer(name="dataset_batch",palette = "Set2"),
                                     p_scvi_denoised_hvg_2,
                                     p_scvi_denoised_hvg_3+scale_fill_brewer(name="dataset_batch",palette = "Set2")),
                                get_plot4_sep(df_pseudotime_list[[7]])[c(3,4)]))+
get_draw_plot(5,get_plot_list(list(p_mnn_denoised_hvg_1+scale_color_brewer(name="dataset_batch",palette = "Set2"),
                                   p_mnn_denoised_hvg_2,
                                   p_mnn_denoised_hvg_3+scale_fill_brewer(name="dataset_batch",palette = "Set2")),
                              get_plot4_sep(df_pseudotime_list[[12]])[c(3,4)]))
for (i in 1:length(use_id)){
  p=p+draw_label(labels[i],x=get_label_pos(i)[1],y=get_label_pos(i)[2],size=30,color="black",hjust = 0,vjust = 1)+
    draw_label(paste0(Methods[use_id[i]],collapse = ""),
               x=get_title_pos(i)[1],
               y=get_title_pos(i)[2],
               size=20,
               color = "black",angle = 90,hjust = 0.5,vjust = 0.5)
}
p

ggsave(p,filename = "./revised_figures/CarDEC_monocyte_Main_fig1.pdf",width = 30,height = 25)
ggsave(p,filename = "./revised_figures/CarDEC_monocyte_Main_fig1.tiff",width = 30,height = 25,compression="lzw")

8.2 Supplementary Figures about monocyte

  1. Raw
plist0=rep(list(),length=9)
plist0[1:3]=list(p_ori_all_1+scale_color_brewer(name="dataset_batch",palette = "Set2")+theme_use,
                 p_ori_all_2,
                 p_ori_all_3+scale_fill_brewer(name="dataset_batch",palette = "Set2")+theme(plot.margin = unit(c(0,0,1,0),"cm")))[1:3]
plist0[4:5]=get_plot4_sep(df_pseudotime_list[[2]])[1:2]
plist0[[6]]=ggplot()+theme_void()+theme(plot.margin = unit(c(0,0,1,0),"cm"))
plist0[7:8]=get_plot4_sep(df_pseudotime_list[[2]])[3:4]
plist0[[9]]=ggplot()+theme_void()
p=ggdraw()+draw_plot(egg::ggarrange(plots = plist0,ncol=3,draw = F),x=0,y=0,width=1,height=1)+
 draw_label("a",x=0,y=1-0.02,size=30,color="black",hjust = 0,vjust = 1)+
 draw_label("b",x=0,y=2/3-0.03,size=30,color="black",hjust = 0,vjust = 1)+
   draw_label("c",x=0,y=1/3-0.03,size=30,color="black",hjust = 0,vjust = 1)
p

ggsave(p,filename = "./revised_figures/CarDEC_monocyte_Supp_fig1.pdf",width = 18,height = 16)
ggsave(p,filename = "./revised_figures/CarDEC_monocyte_Supp_fig1.tiff",width = 18,height = 16,compression="lzw")
  1. All genes
fig_width=30
fig_height=25
labels=letters[1:5]
Methods=c("Raw count HVGs","Raw count All","CarDEC (latent)","CarDEC (denoised HVGs)","CarDEC (denoised All)","scVI (latent)","scVI (denoised HVGs)","scVI (denoised All)","DCA (latent)","DCA (denoised HVGs)","DCA (denoised All)","MNN (denoised HVGs)","MNN (denoised All)","Scanorama (latent)","Scanorama (denoised HVGs)","Scanorama (denoised All)")
use_id=c(5,16,11,8,13)
get_draw_plot=function(plot_id=1,plist0){
  x=0.02
  y=1-plot_id/5
  width=0.98
  height=1/5-0.01 # total number of figures is 12
  pp=draw_plot(egg::ggarrange(plots=plist0,nrow = 1,draw = F,newpage = F),x = x,y = y,width = width,height = height)
  #draw_label(labels[plot_id],x=x,y=y+1/6,hjust =1,vjust = 0.5,size = 35)
  return(pp)
}
get_label_pos=function(plot_id=1){
  x=0
  y=1-plot_id/5
  #draw_label(labels[plot_id],x=x,y=y+1/6,hjust =1,vjust = 0.5,size = 35)
  return(c(x,y+1/5-1/30))
}
get_title_pos=function(plot_id=1){
  x=0.015
  y=1-plot_id/5
  #draw_label(labels[plot_id],x=x,y=y+1/6,hjust =1,vjust = 0.5,size = 35)
  return(c(x,y+1/10-1/60))
}
get_plot_list=function(x,y){
  x0=rep(list(),length=length(x)+length(y))
  x0[1:length(x)]=x[1:3]
  x0[(length(x)+1):length(x0)]=y[1:2]
  return(x0)
}
p=ggdraw()+
  get_draw_plot(1,get_plot_list(list(p_carDEC_denoised_all_1+scale_color_brewer(name="dataset_batch",palette = "Set2"),
                                     p_carDEC_denoised_all_2,
                                     p_carDEC_denoised_all_3+scale_fill_brewer(name="dataset_batch",palette = "Set2")), 
                                get_plot4_sep(df_pseudotime_list[[5]])[c(3,4)]))+
 get_draw_plot(2,get_plot_list(list(p_monocle_scanorama_denoised_all_1+scale_color_brewer(name="dataset_batch",palette = "Set2"),
                                   p_monocle_scanorama_denoised_all_2,
                                   p_monocle_scanorama_denoised_all_3+scale_fill_brewer(name="dataset_batch",palette = "Set2")),
                              get_plot4_sep(df_pseudotime_list[[16]])[c(3,4)]))+
  get_draw_plot(3,get_plot_list(list(p_dca_denoised_all_1+scale_color_brewer(name="dataset_batch",palette = "Set2"),
                                     p_dca_denoised_all_2,
                                     p_dca_denoised_all_3+scale_fill_brewer(name="dataset_batch",palette = "Set2")), 
                                get_plot4_sep(df_pseudotime_list[[11]])[c(3,4)]))+
  get_draw_plot(4,get_plot_list(list(p_scVI_denoised_all_1+scale_color_brewer(name="dataset_batch",palette = "Set2"),
                                     p_scVI_denoised_all_2,
                                     p_scVI_denoised_all_3+scale_fill_brewer(name="dataset_batch",palette = "Set2")), 
                                get_plot4_sep(df_pseudotime_list[[8]])[c(3,4)]))+
  get_draw_plot(5,get_plot_list(list(p_mnn_denoised_all_1+scale_color_brewer(name="dataset_batch",palette = "Set2"),
                                     p_mnn_denoised_all_2,
                                     p_mnn_denoised_all_3+scale_fill_brewer(name="dataset_batch",palette = "Set2")), 
                                get_plot4_sep(df_pseudotime_list[[13]])[c(3,4)]))
 
for (i in 1:length(use_id)){
  p=p+draw_label(labels[i],x=get_label_pos(i)[1],y=get_label_pos(i)[2],size=30,color="black",hjust = 0,vjust = 1)+
    draw_label(paste0(Methods[use_id[i]],collapse = ""),
               x=get_title_pos(i)[1],
               y=get_title_pos(i)[2],
               size=20,
               color = "black",angle = 90,hjust = 0.5,vjust = 0.5)
}
p

ggsave(p,filename = "./revised_figures/CarDEC_monocyte_Supp_fig2.pdf",width = 30,height = 25,limitsize = F)
ggsave(p,filename = "./revised_figures/CarDEC_monocyte_Supp_fig2.tiff",width = 30,height = 25,limitsize = F,compression="lzw")
  1. Latent
fig_width=30
fig_height=25
labels=letters[1:5]
Methods=c("Raw count HVGs","Raw count All","CarDEC (latent)","CarDEC (denoised HVGs)","CarDEC (denoised All)","scVI (latent)","scVI (denoised HVGs)","scVI (denoised All)","DCA (latent)","DCA (denoised HVGs)","DCA (denoised All)","MNN (denoised HVGs)","MNN (denoised All)","Scanorama (latent)","Scanorama (denoised HVGs)","Scanorama (denoised All)")
use_id=c(3,14,9,6,1)
get_draw_plot=function(plot_id=1,plist0){
  x=0.02
  y=1-plot_id/5
  width=0.98
  height=1/5-0.01 # total number of figures is 12
  pp=draw_plot(egg::ggarrange(plots=plist0,nrow = 1,draw = F,newpage = F),x = x,y = y,width = width,height = height)
  #draw_label(labels[plot_id],x=x,y=y+1/6,hjust =1,vjust = 0.5,size = 35)
  return(pp)
}
get_label_pos=function(plot_id=1){
  x=0
  y=1-plot_id/5
  #draw_label(labels[plot_id],x=x,y=y+1/6,hjust =1,vjust = 0.5,size = 35)
  return(c(x,y+1/5-1/30))
}
get_title_pos=function(plot_id=1){
  x=0.015
  y=1-plot_id/5
  #draw_label(labels[plot_id],x=x,y=y+1/6,hjust =1,vjust = 0.5,size = 35)
  return(c(x,y+1/10-1/60))
}
get_plot_list=function(x,y){
  x0=rep(list(),length=length(x)+length(y))
  x0[1:length(x)]=x[1:3]
  x0[(length(x)+1):length(x0)]=y[1:2]
  return(x0)
}
p=ggdraw()+get_draw_plot(1,get_plot_list(list(p_carDEC_latent_1+scale_color_brewer(name="dataset_batch",palette = "Set2"),
                                              p_carDEC_latent_2,
                                              p_carDEC_latent_3+scale_fill_brewer(name="dataset_batch",palette = "Set2")),
                                         get_plot4_sep(df_pseudotime_list[[3]])[c(3,4)]))+
  get_draw_plot(2,get_plot_list(list(p_monocle_scanorama_latent_hvg_1+scale_color_brewer(name="dataset_batch",palette = "Set2"),
                                   p_monocle_scanorama_latent_hvg_2,
                                   p_monocle_scanorama_latent_hvg_3+scale_fill_brewer(name="dataset_batch",palette = "Set2")),
                              get_plot4_sep(df_pseudotime_list[[14]])[c(3,4)]))+
  get_draw_plot(3,get_plot_list(list(p_dca_latent_all_1+scale_color_brewer(name="dataset_batch",palette = "Set2"),
                                     p_dca_latent_all_2,
                                     p_dca_latent_all_3+scale_fill_brewer(name="dataset_batch",palette = "Set2")), 
                                get_plot4_sep(df_pseudotime_list[[9]])[c(3,4)]))+
  get_draw_plot(4,get_plot_list(list(p_scVI_latent_all_1+scale_color_brewer(name="dataset_batch",palette = "Set2"),
                                     p_scVI_latent_all_2,
                                     p_scVI_latent_all_3+scale_fill_brewer(name="dataset_batch",palette = "Set2")), 
                                get_plot4_sep(df_pseudotime_list[[6]])[c(3,4)]))+
  get_draw_plot(5,get_plot_list(list(p_ori_1+scale_color_brewer(name="dataset_batch",palette = "Set2"),
                                     p_ori_2,
                                     p_ori_3+scale_fill_brewer(name="dataset_batch",palette = "Set2")), 
                                get_plot4_sep(df_pseudotime_list[[1]])[c(3,4)]))
for (i in 1:length(use_id)){
  p=p+draw_label(labels[i],x=get_label_pos(i)[1],y=get_label_pos(i)[2],size=30,color="black",hjust = 0,vjust = 1)+
    draw_label(paste0(Methods[use_id[i]],collapse = ""),
               x=get_title_pos(i)[1],
               y=get_title_pos(i)[2],
               size=20,
               color = "black",angle = 90,hjust = 0.5,vjust = 0.5)
}
p

ggsave(p,filename = "./revised_figures/CarDEC_monocyte_Supp_fig3.pdf",width = 30,height = 25,limitsize = F)
ggsave(p,filename = "./revised_figures/CarDEC_monocyte_Supp_fig3.tiff",width = 30,height = 25,limitsize = F,compression="lzw")

8.3 S100A8 and FCGR3A’s feature plots

  1. monocles’ UMAP of denoised counts from HVGs
fig_width=15
fig_height=25
labels=letters[1:13]
Methods=c("Raw count HVGs","Raw count All","CarDEC (latent)","CarDEC (denoised HVGs)","CarDEC (denoised All)","scVI (latent)","scVI (denoised HVGs)","scVI (denoised All)","DCA (latent)","DCA (denoised HVGs)","DCA (denoised All)","MNN (denoised HVGs)","MNN (denoised All)","Scanorama (latent)","Scanorama (denoised HVGs)","Scanorama (denoised All)")
use_id=c(4,15,10,7,12)
#use_id=c(3,9,6,1)
get_draw_plot=function(plot_id=1,plist0){
  x=0.02
  y=1-plot_id/5
  width=0.98
  height=1/5-0.01 # total number of figures is 12
  pp=draw_plot(egg::ggarrange(plots=plist0,nrow = 1,draw = F,newpage = F),x = x,y = y,width = width,height = height)
  #draw_label(labels[plot_id],x=x,y=y+1/6,hjust =1,vjust = 0.5,size = 35)
  return(pp)
}
get_label_pos=function(plot_id=1){
  x=0
  y=1-plot_id/5
  #draw_label(labels[plot_id],x=x,y=y+1/6,hjust =1,vjust = 0.5,size = 35)
  return(c(x,y+1/5-1/100))
}
get_title_pos=function(plot_id=1){
  x=0.015
  y=1-plot_id/5
  #draw_label(labels[plot_id],x=x,y=y+1/6,hjust =1,vjust = 0.5,size = 35)
  return(c(x,y+1/10-1/100))
}
get_plot_list=function(x,y){
  x0=rep(list(),length=length(x)+length(y))
  x0[1:length(x)]=x[1:3]
  x0[(length(x)+1):length(x0)]=y[1:2]
  return(x0)
}
p=ggdraw()
for(i in 1:length(use_id)){
  p=p+get_draw_plot(i,get_plot4_sep(df_pseudotime_list[[use_id[i]]])[c(1,2)])
}
for (i in 1:length(use_id)){
  p=p+draw_label(labels[i],x=get_label_pos(i)[1],y=get_label_pos(i)[2],size=30,color="black",hjust = 0,vjust = 1)+
    draw_label(paste0(Methods[use_id[i]],collapse = ""),
               x=get_title_pos(i)[1],
               y=get_title_pos(i)[2],
               size=20,
               color = "black",angle = 90,hjust = 0.5,vjust = 0.5)
}
ggsave("./revised_figures/CarDEC_monocyte_Supp_fig4.pdf",p,width = 15,height = 25)
ggsave("./revised_figures/CarDEC_monocyte_Supp_fig4.tiff",p,width = 15,height = 25,compression="lzw")
p

  1. monocles’ UMAP of denoised counts from All genes
fig_width=15
fig_height=25
labels=letters[1:13]
Methods=c("Raw count HVGs","Raw count All","CarDEC (latent)","CarDEC (denoised HVGs)","CarDEC (denoised All)","scVI (latent)","scVI (denoised HVGs)","scVI (denoised All)","DCA (latent)","DCA (denoised HVGs)","DCA (denoised All)","MNN (denoised HVGs)","MNN (denoised All)","Scanorama (latent)","Scanorama (denoised HVGs)","Scanorama (denoised All)")
use_id=c(5,16,11,8,13)
get_draw_plot=function(plot_id=1,plist0){
  x=0.02
  y=1-plot_id/5
  width=0.98
  height=1/5-0.01 # total number of figures is 12
  pp=draw_plot(egg::ggarrange(plots=plist0,nrow = 1,draw = F,newpage = F),x = x,y = y,width = width,height = height)
  #draw_label(labels[plot_id],x=x,y=y+1/6,hjust =1,vjust = 0.5,size = 35)
  return(pp)
}
get_label_pos=function(plot_id=1){
  x=0
  y=1-plot_id/5
  #draw_label(labels[plot_id],x=x,y=y+1/6,hjust =1,vjust = 0.5,size = 35)
  return(c(x,y+1/5-1/100))
}
get_title_pos=function(plot_id=1){
  x=0.015
  y=1-plot_id/5
  #draw_label(labels[plot_id],x=x,y=y+1/6,hjust =1,vjust = 0.5,size = 35)
  return(c(x,y+1/10-1/100))
}
get_plot_list=function(x,y){
  x0=rep(list(),length=length(x)+length(y))
  x0[1:length(x)]=x[1:3]
  x0[(length(x)+1):length(x0)]=y[1:2]
  return(x0)
}
p=ggdraw()
for(i in 1:length(use_id)){
  p=p+get_draw_plot(i,get_plot4_sep(df_pseudotime_list[[use_id[i]]])[c(1,2)])
}
for (i in 1:length(use_id)){
  p=p+draw_label(labels[i],x=get_label_pos(i)[1],y=get_label_pos(i)[2],size=30,color="black",hjust = 0,vjust = 1)+
    draw_label(paste0(Methods[use_id[i]],collapse = ""),
               x=get_title_pos(i)[1],
               y=get_title_pos(i)[2],
               size=20,
               color = "black",angle = 90,hjust = 0.5,vjust = 0.5)
}
ggsave("./revised_figures/CarDEC_monocyte_Supp_fig5.pdf",p,width = 15,height = 25)
ggsave("./revised_figures/CarDEC_monocyte_Supp_fig5.tiff",p,width = 15,height = 25,compression="lzw")
p

  1. monocles’ UMAP based on different methods’ latent
fig_width=15
fig_height=25
labels=letters[1:13]
Methods=c("Raw count HVGs","Raw count All","CarDEC (latent)","CarDEC (denoised HVGs)","CarDEC (denoised All)","scVI (latent)","scVI (denoised HVGs)","scVI (denoised All)","DCA (latent)","DCA (denoised HVGs)","DCA (denoised All)","MNN (denoised HVGs)","MNN (denoised All)","Scanorama (latent)","Scanorama (denoised HVGs)","Scanorama (denoised All)")
use_id=c(3,14,9,6,1)
get_draw_plot=function(plot_id=1,plist0){
  x=0.02
  y=1-plot_id/5
  width=0.98
  height=1/5-0.01 # total number of figures is 12
  pp=draw_plot(egg::ggarrange(plots=plist0,nrow = 1,draw = F,newpage = F),x = x,y = y,width = width,height = height)
  #draw_label(labels[plot_id],x=x,y=y+1/6,hjust =1,vjust = 0.5,size = 35)
  return(pp)
}
get_label_pos=function(plot_id=1){
  x=0
  y=1-plot_id/5
  #draw_label(labels[plot_id],x=x,y=y+1/6,hjust =1,vjust = 0.5,size = 35)
  return(c(x,y+1/5-1/100))
}
get_title_pos=function(plot_id=1){
  x=0.015
  y=1-plot_id/5
  #draw_label(labels[plot_id],x=x,y=y+1/6,hjust =1,vjust = 0.5,size = 35)
  return(c(x,y+1/10-1/100))
}
get_plot_list=function(x,y){
  x0=rep(list(),length=length(x)+length(y))
  x0[1:length(x)]=x[1:3]
  x0[(length(x)+1):length(x0)]=y[1:2]
  return(x0)
}
p=ggdraw()
for(i in 1:length(use_id)){
  p=p+get_draw_plot(i,get_plot4_sep(df_pseudotime_list[[use_id[i]]])[c(1,2)])
}
for (i in 1:length(use_id)){
  p=p+draw_label(labels[i],x=get_label_pos(i)[1],y=get_label_pos(i)[2],size=30,color="black",hjust = 0,vjust = 1)+
    draw_label(paste0(Methods[use_id[i]],collapse = ""),
               x=get_title_pos(i)[1],
               y=get_title_pos(i)[2],
               size=20,
               color = "black",angle = 90,hjust = 0.5,vjust = 0.5)
}
ggsave("./revised_figures/CarDEC_monocyte_Supp_fig6.pdf",p,width = 15,height = 25)
ggsave("./revised_figures/CarDEC_monocyte_Supp_fig6.tiff",p,width = 15,height = 25,compression="lzw")
p

  1. Combined above three figures
fig_width=24
fig_height=36#
labels=letters[1:16]
Methods=c("Raw count HVGs","Raw count All","CarDEC (latent)","CarDEC (denoised HVGs)","CarDEC (denoised All)","scVI (latent)","scVI (denoised HVGs)","scVI (denoised All)","DCA (latent)","DCA (denoised HVGs)","DCA (denoised All)","MNN (denoised HVGs)","MNN (denoised All)","Scanorama (latent)","Scanorama (denoised HVGs)","Scanorama (denoised All)")
use_id=c(1,3:5,14:16,6:13)
get_draw_plot=function(plot_id=1,plist0){
  x=ifelse(plot_id%%2==1,0,0.5075)
  y=1-floor((plot_id+1)/2)/8
  width=1/2-0.015
  height=1/8-0.01 # total number of figures is 12
  pp=draw_plot(egg::ggarrange(plots=plist0,ncol = 2,draw = F,newpage = F),x = x,y = y,width = width,height = height)
  #draw_label(labels[plot_id],x=x,y=y+1/6,hjust =1,vjust = 0.5,size = 35)
  return(pp)
}
get_label_pos=function(plot_id=1){
  x=ifelse(plot_id%%2==1,0,0.5075)
  y=1-floor((plot_id+1)/2)/8
  #draw_label(labels[plot_id],x=x,y=y+1/6,hjust =1,vjust = 0.5,size = 35)
  return(c(x,y+1/8-1/100))
}
get_title_pos=function(plot_id=1){
  x=ifelse(plot_id%%2==1,0,0.5075)+0.5/2
  y=1-floor((plot_id+1)/2)/8
  #draw_label(labels[plot_id],x=x,y=y+1/6,hjust =1,vjust = 0.5,size = 35)
  return(c(x,y+1/8-1/300))
}
p=ggdraw()
for(i in 1:length(use_id)){
  p=p+get_draw_plot(i,get_plot4_sep(df_pseudotime_list[[use_id[i]]])[c(1,2)])
}
for (i in 1:length(use_id)){
  p=p+draw_label(labels[i],x=get_label_pos(i)[1],y=get_label_pos(i)[2],size=18,color="black",hjust = 0,vjust = 1)+
    draw_label(paste0(Methods[use_id[i]],collapse = ""),x=get_title_pos(i)[1],y=get_title_pos(i)[2],size=25,color = "black",vjust = 1)
}
p

ggsave(p,filename = "./revised_figures/CarDEC_monocyte_Supp_fig456_combined.pdf",width = 24,height = 36)
ggsave(p,filename = "./revised_figures/CarDEC_monocyte_Supp_fig456_combined.tiff",width = 24,height = 36,compression="lzw")
#save object 
rm(mtx)
rm(output)
rm(adata)
rm(cds)
rm(obj0)
rm(raw.data)
gc()
             used    (Mb) gc trigger    (Mb)   max used    (Mb)
Ncells    7706421   411.6   15080422   805.4   15080422   805.4
Vcells 1642530695 12531.6 3505959062 26748.4 3503411665 26729.0
save.image(file="carDEC_monocyte_final_revised.RData")#include scanorama,carDEC_monocyte_final.RData not include scanorama
load("carDEC_monocyte_final_revised.RData")
sessionInfo()
R version 3.6.1 (2019-07-05)
Platform: x86_64-pc-linux-gnu (64-bit)
Running under: Ubuntu 18.04.3 LTS

Matrix products: default
BLAS:   /usr/lib/x86_64-linux-gnu/blas/libblas.so.3.7.1
LAPACK: /usr/lib/x86_64-linux-gnu/lapack/liblapack.so.3.7.1

locale:
 [1] LC_CTYPE=en_US.UTF-8       LC_NUMERIC=C               LC_TIME=en_SG.UTF-8        LC_COLLATE=en_US.UTF-8     LC_MONETARY=en_SG.UTF-8   
 [6] LC_MESSAGES=en_US.UTF-8    LC_PAPER=en_SG.UTF-8       LC_NAME=C                  LC_ADDRESS=C               LC_TELEPHONE=C            
[11] LC_MEASUREMENT=en_SG.UTF-8 LC_IDENTIFICATION=C       

attached base packages:
 [1] grid      splines   stats4    parallel  stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
 [1] mgcv_1.8-28                 nlme_3.1-140                monocle3_0.2.1              SingleCellExperiment_1.6.0  SummarizedExperiment_1.14.0
 [6] DelayedArray_0.10.0         BiocParallel_1.20.1         matrixStats_0.56.0          GenomicRanges_1.36.0        GenomeInfoDb_1.20.0        
[11] IRanges_2.18.3              S4Vectors_0.22.1            pheatmap_1.0.12             pbapply_1.4-2               liger_0.4.2                
[16] harmony_1.0                 Rcpp_1.0.6                  RColorBrewer_1.1-2          patchwork_1.1.0.9000        SeuratWrappers_0.1.0       
[21] cowplot_1.0.0               ComplexHeatmap_2.1.2        kableExtra_0.9.0            ggjoy_0.4.1                 ggridges_0.5.1             
[26] tidyr_0.8.3                 dplyr_0.8.5                 monocle_2.9.0               DDRTree_0.1.5               irlba_2.3.3                
[31] VGAM_1.1-2                  ggplot2_3.3.3               Biobase_2.44.0              BiocGenerics_0.32.0         Matrix_1.2-18              
[36] reticulate_1.15            

loaded via a namespace (and not attached):
  [1] rappdirs_0.3.1         RANN.L1_2.5.2          nabor_0.5.0            bit64_0.9-7            knitr_1.23             data.table_1.12.8     
  [7] rpart_4.1-15           RCurl_1.98-1.1         snow_0.4-3             RSQLite_2.1.1          RANN_2.6.1             europepmc_0.3         
 [13] combinat_0.0-8         proxy_0.4-23           future_1.12.0          bit_1.1-15.2           enrichplot_1.2.0       spatstat.data_1.4-3   
 [19] xml2_1.3.0             httpuv_1.5.4           assertthat_0.2.1       viridis_0.5.1          xfun_0.19              hms_0.5.0             
 [25] evaluate_0.14          promises_1.0.1         fansi_0.4.1            progress_1.2.2         caTools_1.18.0         readxl_1.3.1          
 [31] igraph_1.2.5           DBI_1.1.0              htmlwidgets_1.3        sparsesvd_0.2          riverplot_0.6          purrr_0.3.3           
 [37] crosstalk_1.0.0        ggpubr_0.2.1           V8_2.3                 deldir_0.1-25          vctrs_0.2.4            remotes_2.1.1         
 [43] ROCR_1.0-7             abind_1.4-5            withr_2.1.2            ggforce_0.1.3          triebeard_0.3.0        sctransform_0.3.1     
 [49] prettyunits_1.1.1      mclust_5.4.5           goftest_1.2-2          mnormt_1.5-6           cluster_2.1.0          DOSE_3.8.2            
 [55] lazyeval_0.2.2         crayon_1.3.4           pkgconfig_2.0.3        slam_0.1-47            labeling_0.3           units_0.6-5           
 [61] tweenr_1.0.1           rlang_0.4.10           globals_0.12.4         lifecycle_0.2.0        miniUI_0.1.1.1         doSNOW_1.0.18         
 [67] rsvd_1.0.0             cellranger_1.1.0       polyclip_1.10-0        lmtest_0.9-37          urltools_1.7.2         zoo_1.8-7             
 [73] base64enc_0.1-3        GlobalOptions_0.1.1    png_0.1-7              viridisLite_0.3.0      rjson_0.2.20           bitops_1.0-6          
 [79] KernSmooth_2.23-15     blob_1.2.0             shape_1.4.4            pdftools_2.3           stringr_1.4.0          qvalue_2.14.1         
 [85] qpdf_1.1               readr_1.3.1            gridGraphics_0.5-0     ggsignif_0.5.0         scales_1.1.0           memoise_1.1.0         
 [91] magrittr_1.5           plyr_1.8.4             ica_1.0-2              gplots_3.0.3           zlibbioc_1.32.0        gdata_2.18.0          
 [97] compiler_3.6.1         HSMMSingleCell_1.4.0   lsei_1.2-0             clue_0.3-57            fitdistrplus_1.0-14    cli_2.0.2             
[103] XVector_0.24.0         listenv_0.7.0          MASS_7.3-51.4          tidyselect_0.2.5       stringi_1.4.6          densityClust_0.3      
[109] yaml_2.2.0             GOSemSim_2.8.0         askpass_1.1            ggrepel_0.8.1          fastmatch_1.1-0        randomcoloR_1.1.0.1   
[115] tools_3.6.1            future.apply_1.2.0     circlize_0.4.8         rstudioapi_0.11        foreach_1.5.0          gridExtra_2.3         
[121] farver_2.0.3           Rtsne_0.15             ggraph_1.0.2           digest_0.6.25          rvcheck_0.1.3          BiocManager_1.30.10   
[127] FNN_1.1.3              shiny_1.3.2            qlcMatrix_0.9.7        egg_0.4.5              later_1.0.0            RcppAnnoy_0.0.16      
[133] httr_1.4.1             AnnotationDbi_1.48.0   rsconnect_0.8.16       psych_1.9.12.31        npsurv_0.4-0           colorspace_1.4-1      
[139] rvest_0.3.4            tensor_1.5             uwot_0.1.8             spatstat.utils_1.17-0  ggplotify_0.0.3        plotly_4.9.0          
[145] xtable_1.8-4           jsonlite_1.6.1         spatstat_1.64-1        UpSetR_1.3.3           R6_2.4.1               pillar_1.4.2          
[151] htmltools_0.4.0        mime_0.9               glue_1.4.0             clusterProfiler_3.10.1 DT_0.7                 codetools_0.2-16      
[157] fgsea_1.8.0            utf8_1.1.4             lattice_0.20-38        tibble_2.1.3           curl_4.3               leiden_0.3.1          
[163] gtools_3.8.2           magick_2.3             zip_2.0.4              GO.db_3.7.0            openxlsx_4.1.4         survival_2.44-1.1     
[169] limma_3.42.2           rmarkdown_1.11         docopt_0.6.1           fastICA_1.2-2          munsell_0.5.0          GenomeInfoDbData_1.2.2
[175] DO.db_2.9              GetoptLong_0.1.8       iterators_1.0.12       reshape2_1.4.3         gtable_0.3.0           Seurat_3.2.2          
LS0tCnRpdGxlOiAiVGhlIHJlc3VsdHMgZm9yIG1vbm9jeXRlcyBkYXRhc2V0IgpzdWJ0aXRsZTogInJhdyBjb3VudCBtYXRyaXgsIENhckRFQywgRENBK2NvbWJhdCwgc2NWSSBhbmQgc2Nhbm9yYW1hIgphdXRob3I6ICBYaWFuZ2ppZSBMaQpkYXRlOiAiYHIgZm9ybWF0KFN5cy50aW1lKCksICclbS8lZC8lWScpYCIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6CiAgICBudW1iZXJfc2VjdGlvbnM6IHllcwogICAgdG9jOiB5ZXMKICBqZWt5bGx0aGF0OjpqZWt5bGxkb3duOgogIGh0bWxfZG9jdW1lbnQ6CiAgICBkZl9wcmludDogcGFnZWQKICAgIHRvYzogeWVzCiAgICBudW1iZXJfc2VjdGlvbnM6IHllcwogIHByZXR0eWRvYzo6aHRtbF9wcmV0dHk6CiAgICB0aGVtZTogY2F5bWFuCiAgICBoaWdobGlnaHQ6IGdpdGh1YgogICAgbWF0aDoga2F0ZXgKICAgIHRvYzogeWVzCi0tLQoKPHN0eWxlPgpwcmUgewogIG1heC1oZWlnaHQ6IDIwMHB4OwogIGZsb2F0OiBsZWZ0OwogIHdpZHRoOiA5MTBweDsKICBvdmVyZmxvdy15OiBhdXRvOwp9CnByZS5yIHsKICBtYXgtaGVpZ2h0OiBub25lOwp9Cjwvc3R5bGU+CgoKKipEYXRhIFN1bW1hcnk6KiogCgpUaGlzIGRhdGFzZXQgd2FzIGdlbmVyYXRlZCBieSBvdXIgZ3JvdXAsIHdoaWNoIGNhbiBiZSBkb3dubG9hZGVkIGZyb20gW0dFTyAoR1NFMTQ2OTc0KV0oaHR0cHM6Ly93d3cubmNiaS5ubG0ubmloLmdvdi9nZW8vcXVlcnkvYWNjLmNnaT9hY2M9R1NFMTQ2OTc0KSBvciBvciBbaHR0cHM6Ly9kcml2ZS5nb29nbGUuY29tL2ZpbGUvZC8xa1I4SGh1Zm9vMmgyT3RvbVc4bjNrTTBnYVFoVlM1NjQvdmlldz91c3A9c2hhcmluZ10oaHR0cHM6Ly9kcml2ZS5nb29nbGUuY29tL2ZpbGUvZC8xa1I4SGh1Zm9vMmgyT3RvbVc4bjNrTTBnYVFoVlM1NjQvdmlldz91c3A9c2hhcmluZykuIFRoaXMgZGF0YXNldCB3YXMgZ2VuZXJhdGVkIGZyb20gaHVtYW4gcGVyaXBoZXJhbCBibG9vZCBtb25vbnVjbGVhciBjbGVhciBjZWxscyBieSBGaWNvbGwgU2VwYXJhdGlvbiBmb2xsb3dlZCBieSBDRDE0IGFuZCBDRDE2IHBvc2l0aXZlIGNlbGwgc2VsZWN0aW9uLiBTaW5jZSB0aGUgQ0QxNCBhbmQgQ0QxNiBhbnRpYm9kaWVzIGFyZSBub3QgMTAwJSBzcGVjaWZpYywgc29tZSBUIGNlbGxzIHdlcmUgYWxzbyBwcmVzZW50IGluIHRoZSBzY1JOQS1zZXEgZGF0YS4gV2UgcGVyZm9ybWVkIGNsdXN0ZXJpbmcgYW5hbHlzaXMgdXNpbmcgbGVpZGVu4oCZcyBhbGdvcml0aG0gZm9yIGVhY2ggYmF0Y2ggYW5kIGlkZW50aWZpZWQgMjg4IFQgY2VsbHMgaW4gdG90YWwgYmFzZWQgb24gdGhlIFQgY2VsbCBtYXJrZXIgZ2VuZXMgQ0QzRCwgQ0QzRSBhbmQgQ0QzRy4gQWZ0ZXJpbmcgcmVtb3ZpbmcgdGhlc2UgMjg4IFQgY2VsbHMsIHRoZXJlIGFyZSAxMCw4NzggY2VsbHMgYW5kIDIxLDI4OSBnZW5lcywgd2hpY2ggd2FzIHByb2Nlc3NlZCBhbmQgc2VxdWVuY2VkIGF0IHRocmVlIGRpZmZlcmVudCBkYXlzLCByZXN1bHRpbmcgaW4gdGhyZWUgYmF0Y2hlcyAoMyw2NDAgY2VsbHMgaW4gVDEsIDQsODMzIGNlbGxzIGluIFQyIGFuZCAyLDQwNSBjZWxscyBpbiBUMykgbGVmdCBpbiB0aGUgcmVtYWluaW5nIGFuYWx5c2lzLiAKCl9fKioqSHVtYW4gbW9ub2N5dGUgcHJlcGFyYXRpb24qKipfXzogTW9ub2N5dGUgcHJlcGFyYXRpb24gdXNlcyBhIG1vZGlmaWNhdGlvbiBvZiBwdWJsaXNoZWQgcHJvdG9jb2xzLiBCcmllZmx5LCB+MjAgbWwgYmxvb2QgZHJhd24gaW4gc29kaXVtIGhlcGFyaW4gd2FzIHByb2Nlc3NlZCBpbW1lZGlhdGVseSBpbiB0aGUgbGFiIGluIHRoZSBDbGluaWNhbCBSZXNlYXJjaCBDZW50ZXIgYXQgQ29sdW1iaWEgVW5pdmVyc2l0eS4gUEJNQ3Mgd2VyZSBpc29sYXRlZCBieSBncmFkaWVudCBGaWNvbGwgcGFxdWUgY2VudHJpZnVnYXRpb24sIHdoaWNoIG1haW50YWlucyBjZWxsIHZpYWJpbGl0eSBhbmQgcHJldmVudHMgZXggdml2byBhY3RpdmF0aW9uIGR1cmluZyBjZWxsIHJlY292ZXJ5LiBDZWxscyB3ZXJlIHN0YWluZWQgd2l0aCBhbnRpYm9kaWVzIGFnYWluc3QgaHVtYW4gSExBRFIsIENEMTQgYW5kIENEMTYgYW5kIG1vbm9jeXRlIHN1YnNldHMgZGVmaW5lZCBhcyBITEFEUitDRDE0KytDRDE2LShjbGFzc2ljYWwpLCBITEFEUitDRDE0KytDRDE2KyAoaW50ZXJtZWRpYXRlKSwgSExBRFIrQ0QxNGRpbS9DRDE2KysgKG5vbmNsYXNzaWNhbCwgcGF0cm9sbGluZyBtb25vY3l0ZSkuIERBUEkgc3RhaW5pbmcgd2FzIHVzZWQgdG8gZXhjbHVkZSBkZWFkIGNlbGxzLiBNb25vY3l0ZXMgd2VyZSBzb3J0ZWQgYnkgYSBCRCBJbmZsdXggU29ydGVyIGludG8gdHViZXMgZm9yIHJlYWwtdGltZSAxMHggR2Vub21pY3MgYW5hbHlzaXMuCgojIFN1bW1hcnkgCgpIZXJlIEkgdXNlZCBtb25vY2xlMyAobW9ub2NsZTNfMC4yLjEpIHRvIGNvbmR1Y3QgdGhlIHBzZXVkb3RpbWUgYW5hbHlzaXMuIAoKPiA8c3BhbiBzdHlsZT0iY29sb3I6cmVkIj4gQ2FyREVDLCBzY1ZJIGFuZCBEQ0EgYXJlIGJvdGggZGVlcCBsZWFybmluZyBiYXNlZCBtZXRob2RzLiBGb3IgZWFjaCBtZXRob2QsIHdlIHVzZWQgYWxsIGdlbmVzIGFzIHRoZSBpbnB1dCwgdGhlIHdheSBvZiBgVXNpbmcgbGF0ZXRuYE9uZSBpcyB0aGUgc3RhbmRhcmQgcGlwbGluZSBmb3IgbW9ub2NsZTMgKGBkZW5vc2llZCBjb3VudGAgLT4gYG5vcm1hbGl6YXRpb25gIC0+IGBzY2FsaW5nYCAtPiBgcGNhYCBkaW1lbnNpb24gcmVkdWN0aW9uIC0+IGB1bWFwIHZpc3VhbGl6YXRpb25gIGJhc2VkIG9uIGBwY2FgIGRpbWVuc2lvbiByZWR1Y3Rpb24pIGFuZCB0aGUgb3RoZXIgbWV0aG9kIHJlcGxjZXMgdGhlIGBwY2FgIGJ5IHRoZSBsYXRlbnQgcmVwcmVzZW50YXRpb24gYW5kIHRoZW4gdW1hcCB2aXN1YWxpemF0aW9uIGJhc2VkIG9uIGxhdGVudCByZXByZXNlbnRhdGlvbi4gPC9zcGFuPgoKCj09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CgotIF9fKioqSFZHcyByYXcqKipfXzogT25seSB1c2luZyBoaWdobHkgdmFyaWFibGUgZ2VuZXMgKEhWRykgYXMgdGhlIGlucHV0cyBmb3IgTW9ub2NsZTMKLSBfXyoqKkFsbCBnZW5lcyByYXcqKipfXzogVXNpbmcgYWxsIGdlbmVzIChIVkcpIGFzIHRoZSBpbnB1dHMgZm9yIE1vbm9jbGUzCi0gX18qKipVc2luZyBsYXRlbnQqKipfXzogUmVwbGNlaW5nIHRoZSBgcGNhYCBieSB0aGUgbGF0ZW50IHJlcHJlc2VudGF0aW9uIGFuZCB0aGVuIHVtYXAgdmlzdWFsaXphdGlvbiBiYXNlZCBvbiBsYXRlbnQgcmVwcmVzZW50YXRpb24gKENhckRFQywgRENBK2NvbWJhdCwgc2NWSSBhbmQgc2Nhbm9yYW1hKS4KLSBfXyoqKkhWRyBkZW5vaXNlZCoqKl9fOiBPbmx5IHVzaW5nIGRlbm9zaW5lZCBleHByZXNzaW9uIGNvdW50IGZyb20gdGhvc2UgaGlnaGx5IHZhcmlhYmxlIGdlbmVzIChIVkdzKSBhcyB0aGUgaW5wdXQgZm9yIG1vbm9jbGUzIGFuZCB0aGVuIGNvbmR1Y3RlZCBzdGFuZGFyZCBwaXBsaW5lIG9mIG1vbm9jbGUzIChDYXJERUMsIERDQSwgc2NWSSBhbmQgc2Nhbm9yYW1hKS4KLSBfXyoqKkFsbCBnZW5lcyBkZW5vaXNlZCoqKl9fOiBVc2VkIGFsbCBkZW5vaXNlZCBleHByZXNzaW9uIHZhbHVlcyBhcyB0aGUgaW5wdXQgZm9yIG1vbm9jbGUzIGFuZCB0aGVuIGNvbmR1Y3RlZCB0aGUgc3RhbmRhcmQgcGlwbGluZSBvZiBtb25vY2xlMyAoQ2FyREVDLCBEQ0EsIGFuZCBzY1ZJKS4KCmBgYHtyfQpvcHRpb25zKHdhcm49LTEpICMgdHVybiBvZmYgd2FybmluZyBtZXNzYWdlIGdsb2JhbGx5Ci5saWJQYXRocyhjKCIvaG9tZS94aWFveGlhbmcvUi94ODZfNjQtcGMtbGludXgtZ251LWxpYnJhcnkvMy41IiwubGliUGF0aHMoKSkpClN5cy5zZXRlbnYoUkVUSUNVTEFURV9QWVRIT05fRU5WPSIvaG9tZS94aWFveGlhbmcvYW5hY29uZGEzL2VudnMvcHkzNiIpIz0iL2hvbWUveGlhb3hpYW5nLy5jb25kYS9lbnZzL0RFU0NWSVIiClN5cy5zZXRlbnYoUkVUSUNVTEFURV9QWVRIT049Ii91c3IvYmluL3B5dGhvbjMiKQojUkVUSUNVTEFURV9QWVRIT049Ii9ob21lL3hpYW94aWFuZy9hbmFjb25kYTMvYmluL3B5dGhvbjMiLAppZiAoIlNldXJhdCIgJWluJSBsb2FkZWROYW1lc3BhY2VzKCkpIGRldGFjaCgicGFja2FnZTpTZXVyYXQiLHVubG9hZCA9IFQpCmR5bi5sb2FkKCIvaG9tZS94aWFveGlhbmcvUi94ODZfNjQtcGMtbGludXgtZ251LWxpYnJhcnkvMy41L3NmL2xpYnMvc2Yuc28iKQojc3VwcHJlc3NQYWNrYWdlU3RhcnR1cE1lc3NhZ2VzKGxpYnJhcnkobW9ub2NsZSxsaWIubG9jID0gIi91c3IvbGliL1IvbW9ub2NsZV9hbHBoYSIpKSMgZGV2dG9vbHM6Omluc3RhbGxfZ2l0aHViKCIiKQojZGV2dG9vbHM6Omluc3RhbGxfZ2l0aHViKCJjb2xlLXRyYXBuZWxsLWxhYi9ERFJUcmVlIiwgcmVmPSJzaW1wbGUtcHB0LWxpa2UiLGxpYj0iL3Vzci9saWIvUi9tb25vY2xlX2FscGhhIikKI2RldnRvb2xzOjppbnN0YWxsX2dpdGh1Yigici1zcGF0aWFsL3NmIikgaWYgCiNpbnN0YWxsLnBhY2thZ2VzKCJ+L0Rvd25sb2Fkcy9tb25vY2xlLXJlbGVhc2UtbW9ub2NsZTNfYWxwaGEvIiwgcmVwb3MgPSBOVUxMLGxpYiA9ICIvdXNyL2xpYi9SL21vbm9jbGVfYWxwaGEiKQpzdXBwcmVzc1BhY2thZ2VTdGFydHVwTWVzc2FnZXMobGlicmFyeShyZXRpY3VsYXRlKSkKI3N1cHByZXNzUGFja2FnZVN0YXJ0dXBNZXNzYWdlcyhsaWJyYXJ5KGRldnRvb2xzKSkKc3VwcHJlc3NQYWNrYWdlU3RhcnR1cE1lc3NhZ2VzKGxpYnJhcnkobW9ub2NsZTMpKQoKI3N1cHByZXNzUGFja2FnZVN0YXJ0dXBNZXNzYWdlcyhsaWJyYXJ5KGZsZXhjbHVzdCkpCiNzdXBwcmVzc1BhY2thZ2VTdGFydHVwTWVzc2FnZXMobGlicmFyeShtY2NsdXN0KSkKc3VwcHJlc3NQYWNrYWdlU3RhcnR1cE1lc3NhZ2VzKGxpYnJhcnkoZHBseXIpKQpzdXBwcmVzc1BhY2thZ2VTdGFydHVwTWVzc2FnZXMobGlicmFyeShnZ2pveSkpCnN1cHByZXNzUGFja2FnZVN0YXJ0dXBNZXNzYWdlcyhsaWJyYXJ5KFZHQU0pKQpzdXBwcmVzc1BhY2thZ2VTdGFydHVwTWVzc2FnZXMobGlicmFyeShrbml0cikpCnN1cHByZXNzUGFja2FnZVN0YXJ0dXBNZXNzYWdlcyhsaWJyYXJ5KGdncGxvdDIpKQpzdXBwcmVzc1BhY2thZ2VTdGFydHVwTWVzc2FnZXMobGlicmFyeShrYWJsZUV4dHJhKSkKc3VwcHJlc3NQYWNrYWdlU3RhcnR1cE1lc3NhZ2VzKGxpYnJhcnkoY293cGxvdCkpCiNweV9pbnN0YWxsKCd1bWFwLWxlYXJuJywgcGlwID0gVCwgcGlwX2lnbm9yZV9pbnN0YWxsZWQgPSBUKQojaW1wb3J0KCJsZWlkZW4iKQojZmlnX3BhdGg9Ii9ob21lL3hpYW94aWFuZy9Eb2N1bWVudHMvREVTQ19wYXBlcl9wcmVwYXJlL0RFU0NfcGFwZXJfZmluYWwvZm9ybWFsX3JldmlzZWQvZmlndXJlc19zZXAvIgpkYXRhZGlycGF0aD0iLi8iCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvPVQpCmBgYAoKCmBgYHtyfQpkZl9wc2V1ZG90aW1lX2xpc3Q9bGlzdCgpCmBgYAoKYGBge3IsZWNobz1GLGluY2x1ZGU9VCxldmFsPVR9CmdldF9wX25ldyA9ZnVuY3Rpb24oeCx4Mj1OVUxMKSB7CiByZXMxPXNhcHBseSh4LGZ1bmN0aW9uKGkwKSBpZmVsc2UoaTA8PTAsIjwyLjJlLTE2IixzY2FsZXM6OnNjaWVudGlmaWMoaTAsZGlnaXRzID0gMykpKSAKIHJlczI9cmVwKGMoIiIpLGxlbmd0aD1sZW5ndGgocmVzMSkpCiBpZighaXMubnVsbCh4MikpewogICByZXMyPXJvdW5kKHgyLDMpIAogfQogcmV0dXJuKHBhc3RlMChyZXMyLCIgKCIscmVzMSwiKSIpKQp9CgpudW1fbWV0aG9kcz0xNiNvcmlnaW5hbCAxMwpTdGFibGU1PWRhdGEuZnJhbWUoTWV0aG9kPWMoIlJhdyBjb3VudCBIVkdzIiwiUmF3IGNvdW50IEFsbCIsIkNhckRFQyAobGF0ZW50KSIsIkNhckRFQyAoZGVub2lzZWQgSFZHcykiLCJDYXJERUMgKGRlbm9pc2VkIEFsbCkiLCJzY1ZJIChsYXRlbnQpIiwic2NWSSAoZGVub2lzZWQgSFZHcykiLCJzY1ZJIChkZW5vaXNlZCBBbGwpIiwiRENBIChsYXRlbnQpIiwiRENBIChkZW5vaXNlZCBIVkdzKSIsIkRDQSAoZGVub2lzZWQgQWxsKSIsIk1OTiAoZGVub2lzZWQgSFZHcykiLCJNTk4gKGRlbm9pc2VkIEFsbCkiLCJTY2Fub3JhbWEgKGxhdGVudCkiLCJTY2Fub3JhbWEgKGRlbm9pc2VkIEhWR3MpIiwiU2Nhbm9yYW1hIChkZW5vaXNlZCBBbGwpIiksCiAgICAgICAgICAgICAgICAgIGBUMSB2LnMuIFQyYD1yZXAoIjwyLjJlLTE2IixsZW5ndGg9bnVtX21ldGhvZHMpLAogICAgICAgICAgICAgICAgICBgVDEgdi5zLiBUM2A9cmVwKCI8Mi4yZS0xNiIsbGVuZ3RoPW51bV9tZXRob2RzKSwKICAgICAgICAgICAgICAgICAgYFQyIHYucy4gVDNgPXJlcCgiPDIuMmUtMTYiLGxlbmd0aD1udW1fbWV0aG9kcyksc3RyaW5nc0FzRmFjdG9ycyA9IEYpCnJvd25hbWVzKFN0YWJsZTUpPVN0YWJsZTUkTWV0aG9kCiN0YWJsZTUgJT4lCiMgIGthYmxlKCkgJT4lCiMgIGthYmxlX3N0eWxpbmcoKQpgYGAKCgpgYGB7cn0KIyBsb2FkIG5lY2Vzc2F5IGZ1bmN0aW9uCiNzb3VyY2UoIi9tZWRpYS94aWFveGlhbmcvRC9ERVNDX3JlcHJvZHVjaWJsZV9maWxlL2hlbHBmdW5jX25ldy5SIikKI3NvdXJjZSgiL21lZGlhL3hpYW94aWFuZy9EL1VwZW5uX2NvbXB1dGVyX2JhY2t1cC9Eb2N1bWVudHMvSHVtYW5fSGVhcnRfUHJvamVjdC9oZWFydC9IZWFydF9yZXN1bHRfdXBkYXRlZC9oZWxwZnVuY19uZXcuUiIpCm9sZD10aGVtZV9zZXQodGhlbWVfYncoKSt0aGVtZShzdHJpcC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGw9IndoaXRlIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxlZ2VuZC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhbmVsLmdyaWQgPWVsZW1lbnRfYmxhbmsoKSkpCgpCYXRjaEtMPWZ1bmN0aW9uKGRmLGRpbWVuc2lvbkRhdGE9TlVMTCxyZXBsaWNhdGVzPTIwMCxuX25laWdoYm9ycz0xMDAsbl9jZWxscz0xMDAsYmF0Y2g9IkJhdGNoSUQiKXsKICAjZW50cm9weSBvZiBiYXRjaCBtaXhpaW5nCiAgI3JlcGxpY2F0ZXMgaXMgdGhlIG51bWJlciBvZiBib29zdHJhcCB0aW1lcwogICNuX25laWdoYm9ycyBpcyB0aGUgbnVtYmVyIG9mIG5lYXJlc3QgbmVpZ2hib3VycyBvZiBjZWxsKGZyb20gYWxsIGJhdGNocykKICAjbl9jZWxscyBpcyB0aGUgbnVtYmVyIG9mIHJhbmRvbWx5IHBpY2tlZCBjZWxscwogIGlmIChpcy5udWxsKGRpbWVuc2lvbkRhdGEpKXsKICAgICAgICB0c25lZGF0YT1hcy5tYXRyaXgoZGZbLGMoInRTTkVfMSIsInRTTkVfMiIpXSkKICB9ZWxzZXsKICAgICAgICB0c25lZGF0YT1hcy5tYXRyaXgoZGltZW5zaW9uRGF0YSkKICB9CiAgYmF0Y2hkYXRhPWZhY3Rvcihhcy52ZWN0b3IoZGZbLGJhdGNoXSkpCiAgdGFibGUuYmF0Y2hkYXRhPWFzLm1hdHJpeCh0YWJsZShiYXRjaGRhdGEpKVssMV0KICB0bXAwMD10YWJsZS5iYXRjaGRhdGEvc3VtKHRhYmxlLmJhdGNoZGF0YSkjcHJvcG9ydGF0aW9uIG9mIHBvcHVsYXRpb24KICBuPWRpbShkZilbMV0KICBLTD1zYXBwbHkoMTpyZXBsaWNhdGVzLGZ1bmN0aW9uKHgpewogICAgYm9vdHNhbXBsZXM9c2FtcGxlKDE6bixuX2NlbGxzKQogICAgI25lYXJlc3Q9bm4yKHRzbmVkYXRhLHRzbmVkYXRhW2Jvb3RzYW1wbGVzLF0saz1uX25laWdoYm9ycykKICAgIG5lYXJlc3Q9bmFib3I6Omtubih0c25lZGF0YSx0c25lZGF0YVtib290c2FtcGxlcyxdLGs9bWluKDUqbGVuZ3RoKHRtcDAwKSxuX25laWdoYm9ycykpCiAgICBLTF94PXNhcHBseSgxOmxlbmd0aChib290c2FtcGxlcyksZnVuY3Rpb24oeSl7CiAgICAgIGlkPW5lYXJlc3Qkbm4uaWR4W3ksXQogICAgICB0bXA9YXMubWF0cml4KHRhYmxlKGJhdGNoZGF0YVtpZF0pKVssMV0KICAgICAgdG1wPXRtcC9zdW0odG1wKQogICAgICByZXR1cm4oc3VtKHRtcCpsb2cyKHRtcC90bXAwMCksbmEucm0gPSBUKSkKICAgIH0pCiAgICByZXR1cm4obWVhbihLTF94LG5hLnJtID0gVCkpCiAgfSkKICByZXR1cm4oS0wpCn0KYGBgCgpgYGB7cn0KQ29udmVydF90b19zZXVyYXQzPWZ1bmN0aW9uKGFkYXRhKXsKICBzdXBwcmVzc1BhY2thZ2VTdGFydHVwTWVzc2FnZXMobGlicmFyeSgiU2V1cmF0IixsaWIubG9jID0gIi91c3IvbGliL1Ivc2VsZl9saWJyYXJ5LyIpKQogIG10eD1weV90b19yKGFkYXRhJFgkVCR0b2NzYygpKQogIGNlbGxpbmZvPXB5X3RvX3IoYWRhdGEkb2JzKQogIGdlbmVpbmZvPXB5X3RvX3IoYWRhdGEkdmFyKQogIGNvbG5hbWVzKG10eCk9Y2VsbGluZm8kY2VsbG5hbWUKICByb3duYW1lcyhtdHgpPXJvd25hbWVzKGdlbmVpbmZvKQogIG9iaj1DcmVhdGVTZXVyYXRPYmplY3QobXR4LG1ldGEuZGF0YSA9IGNlbGxpbmZvWywhY29sbmFtZXMoY2VsbGluZm8pJWluJWMoIm5fZ2VuZXMiLCJuX2NvdW50cyIpLGRyb3A9Rl0sbWluLmZlYXR1cmVzICA9IDEpCiAgcmV0dXJuKG9iaikKfQpnZXR3ZCgpCmBgYAoKCmBgYHtyfQpnZXRfcGxvdDQ9ZnVuY3Rpb24oZGYwMCl7CiAgcDE9Z2dwbG90KCkrZ2VvbV9wb2ludChkYXRhID1kZjAwLGFlcyh4PVVNQVBfMSx5PVVNQVBfMixjb2xvcj1GQ0dSM0EpLHNpemU9MC4wMSkrCiAgICBzY2FsZV9jb2xvcl9ncmFkaWVudChsb3c9ImdyZXkiLGhpZ2g9InJlZCIpKwogICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIpKwogICAgZ3VpZGVzKGNvbG9yPWd1aWRlX2NvbG9yYmFyKHRpdGxlLnZqdXN0ID0gMC43KSkKICAKICBwMj1nZ3Bsb3QoKStnZW9tX3BvaW50KGRhdGEgPWRmMDAsYWVzKHg9VU1BUF8xLHk9VU1BUF8yLGNvbG9yPVMxMDBBOCksc2l6ZT0wLjAxKSsKICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50KGxvdz0iZ3JleSIsaGlnaD0icmVkIikrCiAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIikrCiAgICAgZ3VpZGVzKGNvbG9yPWd1aWRlX2NvbG9yYmFyKHRpdGxlLnZqdXN0ID0gMC43KSkKICAKICBwMz1nZ3Bsb3QoZGF0YSA9ZGYwMCxhZXMoeD1wc2V1ZG90aW1lLHk9RkNHUjNBKSkrCiAgICAgIGdlb21fcG9pbnQoYWVzKGNvbG9yPUJhdGNoSUQpLHNpemU9MC4wMSkrCiAgICAgIGd1aWRlcyhjb2xvcj1ndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID0gbGlzdChzaXplPTUpKSkrCiAgICAgIGdlb21fc21vb3RoKGFlcyhjb2xvcj1CYXRjaElEKSxtZXRob2Q9ImdhbSIsZm9ybXVsYSA9IHkgfiBzKHgsIGJzPSJjcyIpKSsKICAgICAgIGdlb21fc21vb3RoKGNvbG9yPSJibGFjayIsbWV0aG9kPSJnYW0iLGZvcm11bGEgPSB5IH4gcyh4LCBicz0iY3MiKSxzaXplPTAuNSkrCiAgICAgIGdndGl0bGUoIiIpK3hsYWIoIlBzZXVkb3RpbWUiKSt0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT0xOCxmYWNlPSJib2xkIixoanVzdD0wLjUpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT0xNSxmYWNlPSJib2xkIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwbG90Lm1hcmdpbiA9IHVuaXQoYygwLDEsMCwwKSwiY20iKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkrCiAgICBzY2FsZV9jb2xvcl9icmV3ZXIocGFsZXR0ZSA9ICJTZXQyIikKICAKICBwND1nZ3Bsb3QoZGF0YSA9ZGYwMCxhZXMoeD1wc2V1ZG90aW1lLHk9UzEwMEE4KSkrCiAgICAgIGdlb21fcG9pbnQoYWVzKGNvbG9yPUJhdGNoSUQpLHNpemU9MC4wMSkrCiAgICAgIGd1aWRlcyhjb2xvcj1ndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID0gbGlzdChzaXplPTUpKSkrCiAgICAgIGdlb21fc21vb3RoKGFlcyhjb2xvcj1CYXRjaElEKSxtZXRob2Q9ImdhbSIsZm9ybXVsYSA9IHkgfiBzKHgsIGJzPSJjcyIpKSsKICAgICAgIGdlb21fc21vb3RoKGNvbG9yPSJibGFjayIsbWV0aG9kPSJnYW0iLGZvcm11bGEgPSB5IH4gcyh4LCBicz0iY3MiKSxzaXplPTAuNSkrCiAgICAgIGdndGl0bGUoIiIpK3hsYWIoIlBzZXVkb3RpbWUiKSt0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT0xOCxmYWNlPSJib2xkIixoanVzdD0wLjUpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT0xNSxmYWNlPSJib2xkIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpK3NjYWxlX2NvbG9yX2JyZXdlcihwYWxldHRlID0gIlNldDIiKQogIAogIHA9ZWdnOjpnZ2FycmFuZ2UocDEscDMscDIscDQsbmNvbD00LGRyYXc9RikKICByZXR1cm4ocCkKfQoKZ2V0X3Bsb3Q0X3NlcD1mdW5jdGlvbihkZjAwKXsKICBwMT1nZ3Bsb3QoKStnZW9tX3BvaW50KGRhdGEgPWRmMDAsYWVzKHg9VU1BUF8xLHk9VU1BUF8yLGNvbG9yPUZDR1IzQSksc2l6ZT0wLjAxKSsKICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50KGxvdz0iZ3JleSIsaGlnaD0icmVkIikrCiAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIikrCiAgICBndWlkZXMoY29sb3I9Z3VpZGVfY29sb3JiYXIodGl0bGUudmp1c3QgPSAwLjcpKQogIAogIHAyPWdncGxvdCgpK2dlb21fcG9pbnQoZGF0YSA9ZGYwMCxhZXMoeD1VTUFQXzEseT1VTUFQXzIsY29sb3I9UzEwMEE4KSxzaXplPTAuMDEpKwogICAgc2NhbGVfY29sb3JfZ3JhZGllbnQobG93PSJncmV5IixoaWdoPSJyZWQiKSsKICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiKSsKICAgICBndWlkZXMoY29sb3I9Z3VpZGVfY29sb3JiYXIodGl0bGUudmp1c3QgPSAwLjcpKQogIAogIHAzPWdncGxvdChkYXRhID1kZjAwLGFlcyh4PXBzZXVkb3RpbWUseT1GQ0dSM0EpKSsKICAgICAgZ2VvbV9wb2ludChhZXMoY29sb3I9QmF0Y2hJRCksc2l6ZT0wLjA1KSsKICAgICAgZ3VpZGVzKGNvbG9yPWd1aWRlX2xlZ2VuZChvdmVycmlkZS5hZXMgPSBsaXN0KHNpemU9NSkpKSsKICAgICAgZ2VvbV9zbW9vdGgoYWVzKGNvbG9yPUJhdGNoSUQpLG1ldGhvZD0iZ2FtIixmb3JtdWxhID0geSB+IHMoeCwgYnM9ImNzIikpKwogICAgICAgZ2VvbV9zbW9vdGgoY29sb3I9ImJsYWNrIixtZXRob2Q9ImdhbSIsZm9ybXVsYSA9IHkgfiBzKHgsIGJzPSJjcyIpLHNpemU9MC41KSsKICAgICAgZ2d0aXRsZSgiIikreGxhYigiUHNldWRvdGltZSIpK3RoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTE4LGZhY2U9ImJvbGQiLGhqdXN0PTAuNSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTE1LGZhY2U9ImJvbGQiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICNwbG90Lm1hcmdpbiA9IHVuaXQoYygwLDEsMCwwKSwiY20iKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkrCiAgICBzY2FsZV9jb2xvcl9icmV3ZXIocGFsZXR0ZSA9ICJTZXQyIikKICBwND1nZ3Bsb3QoZGF0YSA9ZGYwMCxhZXMoeD1wc2V1ZG90aW1lLHk9UzEwMEE4KSkrCiAgICAgIGdlb21fcG9pbnQoYWVzKGNvbG9yPUJhdGNoSUQpLHNpemU9MC4wNSkrCiAgICAgIGd1aWRlcyhjb2xvcj1ndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID0gbGlzdChzaXplPTUpKSkrCiAgICAgIGdlb21fc21vb3RoKGFlcyhjb2xvcj1CYXRjaElEKSxtZXRob2Q9ImdhbSIsZm9ybXVsYSA9IHkgfiBzKHgsIGJzPSJjcyIpKSsKICAgICAgIGdlb21fc21vb3RoKGNvbG9yPSJibGFjayIsbWV0aG9kPSJnYW0iLGZvcm11bGEgPSB5IH4gcyh4LCBicz0iY3MiKSxzaXplPTAuNSkrCiAgICAgIGdndGl0bGUoIiIpK3hsYWIoIlBzZXVkb3RpbWUiKSt0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT0xOCxmYWNlPSJib2xkIixoanVzdD0wLjUpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT0xNSxmYWNlPSJib2xkIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpKwogICAgc2NhbGVfY29sb3JfYnJld2VyKHBhbGV0dGUgPSAiU2V0MiIpCiAgcmV0dXJuKGxpc3QocDEscDIscDMscDQpKQp9CgpgYGAKCgoKCmBgYHtyfQphZD1pbXBvcnQoImFubmRhdGEiLGNvbnZlcnQgPSBGQUxTRSkKYWRhdGE9YWQkcmVhZF9oNWFkKCIuLi8uLi9kY2FfdGVzdC5oNWFkIikKb2JqMD1Db252ZXJ0X3RvX3NldXJhdDMoYWRhdGEpCm9iajA9Tm9ybWFsaXplRGF0YShvYmowLHZlcmJvc2UgPSBGKQpyYXcuZGF0YT1vYmowQGFzc2F5cyRSTkFAY291bnRzCmBgYAoKYGBge3J9Cm1hcHJ1bGVzPWMoIjIwMTdfMDgwMSI9IlQxIiwiMjAxN18xMDE3Ij0iVDIiLCIyMDE3XzExMjAiPSJUMyIpCm1hcHJ1bGVzCmBgYAoKSGVyZSB3ZSBjb21wYXJlZCBkaWZmZXJlbnQgbWV0aG9kcywgaW5jbHVkaW5nIGBEQ0FgIGFuZCBgc2NWSWAuIAoKYGBge3J9Cmh2Z19nZW5lcz1yZWFkLnRhYmxlKCIuLi9maW5hbF9wcm9jZXNzZWRfcmVzdWx0cy9DYXJERUNfaHZnX3VzZWQudHN2IixoZWFkZXIgPSBULHNlcD0iXHQiLHN0cmluZ3NBc0ZhY3RvcnMgPSBGKQpodmdfZ2VuZXM9c3Vic2V0KGh2Z19nZW5lcyxWYXJpYW5jZS5UeXBlPT0iSFZHIikgI3RvcCAyMDAwIGdlbmVzIApgYGAKCiMgTW9ub2NsZTMgZm9yIGByYXcgZGF0YWAKIyMgSFZHcyByYXcgCgpgYGB7cn0KY2VsbC5tZXRhLmRhdGE9b2JqMEBtZXRhLmRhdGEKY2VsbC5tZXRhLmRhdGEkZGF0YXNldF9iYXRjaD1wbHlyOjptYXB2YWx1ZXMoY2VsbC5tZXRhLmRhdGEkYmF0Y2hfbGFiZWwsbmFtZXMobWFwcnVsZXMpLG1hcHJ1bGVzKQpnZW5lX2Fubj1kYXRhLmZyYW1lKGdlbmVfc2hvcnRfbmFtZSA9IG1ha2UudW5pcXVlKHJvd25hbWVzKHJhdy5kYXRhKSkscm93Lm5hbWVzID0gbWFrZS51bmlxdWUocm93bmFtZXMocmF3LmRhdGEpKSkKI3BkIDwtIG5ldygiQW5ub3RhdGVkRGF0YUZyYW1lIixkYXRhPWNlbGwubWV0YS5kYXRhKQojZmQgPC0gbmV3KCJBbm5vdGF0ZWREYXRhRnJhbWUiLGRhdGE9Z2VuZV9hbm4pCmNkcyA8LSBuZXdfY2VsbF9kYXRhX3NldChyYXcuZGF0YVtyb3duYW1lcyhyYXcuZGF0YSklaW4laHZnX2dlbmVzJGdlbmVuYW1lLF0sIAogICAgICAgICAgICAgICAgICAgICAgICAgY2VsbF9tZXRhZGF0YSA9IGNlbGwubWV0YS5kYXRhLAogICAgICAgICAgICAgICAgICAgICAgICAgZ2VuZV9tZXRhZGF0YSA9Z2VuZV9hbm5bZ2VuZV9hbm4kZ2VuZV9zaG9ydF9uYW1lJWluJWh2Z19nZW5lcyRnZW5lbmFtZSwsZHJvcD1GXSkKIyMgU3RlcCAxOiBOb3JtYWxpemUgYW5kIHByZS1wcm9jZXNzIHRoZSBkYXRhCmNkcyA8LSBwcmVwcm9jZXNzX2NkcyhjZHMsIG51bV9kaW0gPSAzMixtZXRob2Q9IlBDQSIsbm9ybV9tZXRob2Q9ImxvZyIsdmVyYm9zZSA9IEYpCiMjIFN0ZXAgMjogUmVtb3ZlIGJhdGNoIGVmZmVjdHMgd2l0aCBjZWxsIGFsaWdubWVudAojI2NkcyA8LSBhbGlnbl9jZHMoY2RzLCBhbGlnbm1lbnRfZ3JvdXAgPSAiQmF0Y2hJRCIsIHJlc2lkdWFsX21vZGVsX2Zvcm11bGFfc3RyID0gTlVMTCkKIyMgU3RlcCAzOiBSZWR1Y2UgdGhlIGRpbWVuc2lvbnMgdXNpbmcgVU1BUApjZHMgPC0gcmVkdWNlX2RpbWVuc2lvbihjZHMscmVkdWN0aW9uX21ldGhvZCA9ICJVTUFQIixwcmVwcm9jZXNzX21ldGhvZD0iUENBIix2ZXJib3NlID0gRikKCiMjIFN0ZXAgNDogQ2x1c3RlciB0aGUgY2VsbHMKY2RzIDwtIGNsdXN0ZXJfY2VsbHMoY2RzLHJlZHVjdGlvbl9tZXRob2QgPSJVTUFQIixjbHVzdGVyX21ldGhvZCA9ICJsZWlkZW4iLHZlcmJvc2UgPSBGKQojIENvbnN0cnVjdCB0aGUgZ3JhcGgKIyBOb3RlIHRoYXQsIGZvciB0aGUgcmVzdCBvZiB0aGUgY29kZSB0byBydW4sIHRoZSBncmFwaCBzaG91bGQgYmUgZnVsbHkgKHBhcnRpb25seSkgY29ubmVjdGVkCiMjIFN0ZXAgNTogTGVhcm4gYSBncmFwaApjZHMgPC0gbGVhcm5fZ3JhcGgoY2RzLCB1c2VfcGFydGl0aW9uID0gVCx2ZXJib3NlID0gRikKY29sRGF0YShjZHMpJGNsdXN0ZXJzPWNkc0BjbHVzdGVycyRVTUFQJGNsdXN0ZXJzCnAxPXBsb3RfY2VsbHMoY2RzLGNvbG9yX2NlbGxzX2J5ID0gInBhcnRpdGlvbiIsbGFiZWxfY2VsbF9ncm91cHMgPSBGKSt0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIikKcDI9cGxvdF9jZWxscyhjZHMsY29sb3JfY2VsbHNfYnkgPSAiY2x1c3RlcnMiLGxhYmVsX2NlbGxfZ3JvdXBzPUYsZ3JhcGhfbGFiZWxfc2l6ZT0yLCBsYWJlbF9sZWF2ZXM9RixsYWJlbF9icmFuY2hfcG9pbnRzPUYpK3RoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiKQpwPWNvd3Bsb3Q6OnBsb3RfZ3JpZChwMSxwMixhbGlnbiA9ICJoIixuY29sID0gMykKYGBgCgpgYGB7ciBmaWcuaGVpZ2h0PTUsZmlnLndpZHRoPTE4fQpwCmBgYAoKYGBge3J9CiMjIFN0ZXAgNjogT3JkZXIgY2VsbHMKIyBhIGhlbHBlciBmdW5jdGlvbiB0byBpZGVudGlmeSB0aGUgcm9vdCBwcmluY2lwYWwgcG9pbnRzOgpnZXRfZWFybGllc3RfcHJpbmNpcGFsX25vZGUgPC0gZnVuY3Rpb24oY2RzLCBjbHVzdGVyPWMoIjEiLCI1IikpewogIHJvb3RfcHJfbm9kZXM9c2FwcGx5KGNsdXN0ZXIsZnVuY3Rpb24oaWkpewogICAgY2VsbF9pZHMgPC0gd2hpY2goY29sRGF0YShjZHMpWywgImNsdXN0ZXJzIl0gJWluJWlpKQogIAogIGNsb3Nlc3RfdmVydGV4IDwtY2RzQHByaW5jaXBhbF9ncmFwaF9hdXhbWyJVTUFQIl1dJHByX2dyYXBoX2NlbGxfcHJval9jbG9zZXN0X3ZlcnRleAogIAogIGNsb3Nlc3RfdmVydGV4IDwtIGFzLm1hdHJpeChjbG9zZXN0X3ZlcnRleFtjb2xuYW1lcyhjZHMpLCBdKQogIHJvb3RfcHJfbm9kZXMgPC1pZ3JhcGg6OlYocHJpbmNpcGFsX2dyYXBoKGNkcylbWyJVTUFQIl1dKSRuYW1lW2FzLm51bWVyaWMobmFtZXMod2hpY2gubWF4KHRhYmxlKGNsb3Nlc3RfdmVydGV4W2NlbGxfaWRzLF0pKSkpXQogIH0pCiAgcm9vdF9wcl9ub2Rlcwp9CiMgcm9vdCBjZWxscwppZHM9Z2V0X2VhcmxpZXN0X3ByaW5jaXBhbF9ub2RlKGNkcyxjbHVzdGVyPWMoIjEiLCIzIiwiNCIpKQpjZHMgPC0gb3JkZXJfY2VsbHMoY2RzLHJvb3RfcHJfbm9kZXMgPSBpZHMpCiNwbG90X2NlbGxzKGNkcyxjb2xvcl9jZWxsc19ieSA9ICJwc2V1ZG90aW1lIikKYGBgCgpgYGB7cixmaWcuaGVpZ2h0PTUsZmlnLndpZHRoPTE4fQpjb2xEYXRhKGNkcykkcHNldWRvdGltZT1wc2V1ZG90aW1lKGNkcykKY29sRGF0YShjZHMpJFBzZXVkb3RpbWU9Y29sRGF0YShjZHMpJHBzZXVkb3RpbWUvbWF4KGNvbERhdGEoY2RzKSRwc2V1ZG90aW1lLG5hLnJtID0gVCkKZGZfZGVuPXBEYXRhKGNkcylbLGMoIlBzZXVkb3RpbWUiLCJkYXRhc2V0X2JhdGNoIildCmRmX2Rlbj1hcy5kYXRhLmZyYW1lKGRmX2RlblshaXMuaW5maW5pdGUoZGZfZGVuJFBzZXVkb3RpbWUpLF0pCgpzZXQuc2VlZCgxMCkKdGhlbWVfdXNlPXRoZW1lKGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9MTYpLAogICAgICAgICAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9MjApKQoKcF9vcmlfMT1wbG90X2NlbGxzKGNkcyxjb2xvcl9jZWxsc19ieSA9ICJkYXRhc2V0X2JhdGNoIixncmFwaF9sYWJlbF9zaXplPTAsYWxwaGE9MSxjZWxsX3NpemUgPSAwLjYpKwogIGd1aWRlcyhjb2xvdXIgPSBndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID0gbGlzdChhbHBoYT0wLjcsIHNpemU9NSkpKSsKICB0aGVtZV91c2UrCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIpK3RoZW1lKGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKICAgICAgICAgIApwX29yaV8yPXBsb3RfY2VsbHMoY2RzLGNvbG9yX2NlbGxzX2J5ID0gIlBzZXVkb3RpbWUiLGxhYmVsX2JyYW5jaF9wb2ludHM9VCxncmFwaF9sYWJlbF9zaXplPTIsYWxwaGE9MSxjZWxsX3NpemUgPSAwLjYpKwogICAgICAgICAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIiwKICAgICAgICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQodmp1c3QgPSAwLjIpLAogICAgICAgICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KGFuZ2xlPS01MCApLAogICAgICAgICAgICAgICAgICBsZWdlbmQua2V5LmhlaWdodCA9IHVuaXQoMC41LCJjbSIpLAogICAgICAgICAgICAgICAgICBsZWdlbmQua2V5LndpZHRoID0gdW5pdCgxLCJjbSIpKSsKICAgICAgICAgICAgZ3VpZGVzKGNvbG9yID0gZ3VpZGVfY29sb3VyYmFyKGxhYmVsLnBvc2l0aW9uID0gInRvcCIpKSt0aGVtZV91c2UKCnBfb3JpXzM9Z2dwbG90KGRhdGE9ZGZfZGVuKStnZW9tX2RlbnNpdHkoYWVzKHg9UHNldWRvdGltZSxmaWxsPWRhdGFzZXRfYmF0Y2gpLGFscGhhPTAuNykrCiAgICAgICAgICAgIHNjYWxlX3lfY29udGludW91cyhleHBhbmQgPSBjKDAsMCkpKwogICAgICAgICAgICBzY2FsZV94X2NvbnRpbnVvdXMoZXhwYW5kID0gYygwLDApKSsKICAgICAgICAgICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJ0b3AiKSt0aGVtZV91c2UKCnBfbW9ub2NsZV9vcmk9ZWdnOjpnZ2FycmFuZ2UocF9vcmlfMSxwX29yaV8yLHBfb3JpXzMsbmNvbD0zLGRyYXc9RikKYGBgCgpgYGB7cn0KIyBwcmludGVkIGhvdyBtYW55IGNlbGxzIHdpdGggbm8gcHNldWRvdGltZQp0YWJsZShhcy5udW1lcmljKGlzLmluZmluaXRlKHBEYXRhKGNkcylbLGMoInBzZXVkb3RpbWUiKV0pKSkgIzAgbWVhbiBub3JtYWwgcHNldWRvdGltZSBhbmQgMSBtZWFucyBpbmZpbml0eS4KYGBgCgpgYGB7ciBmaWcuaGVpZ2h0PTUsZmlnLndpZHRoPTE4fQpwX21vbm9jbGVfb3JpCmBgYAoKYGBge3J9CmNkc19leHBycz1GZXRjaERhdGEob2JqMCx2YXJzID0gYygiRkNHUjNBIiwiUzEwMEE4IikpCmRmMD1kYXRhLmZyYW1lKGNiaW5kKHBzZXVkb3RpbWU9cERhdGEoY2RzKSRQc2V1ZG90aW1lLGNkc19leHBycykpCiNjZHNfZXhwcnM9YXMubWF0cml4KFNpbmdsZUNlbGxFeHBlcmltZW50Ojpjb3VudHMoY2RzKVtjKCJGQ0dSM0EiLCJTMTAwQTgiKSxdKQojZGYwPWRhdGEuZnJhbWUoY2JpbmQocHNldWRvdGltZT1wRGF0YShjZHMpJFBzZXVkb3RpbWUsbG9nMXAodChjZHNfZXhwcnMpL3NpemVfZmFjdG9ycyhjZHMpKSkpCmRmMCRVTUFQXzE9cmVkdWNlZERpbXMoY2RzKSRVTUFQWywxXQpkZjAkVU1BUF8yPXJlZHVjZWREaW1zKGNkcykkVU1BUFssMl0KZGYwJEJhdGNoSUQ9cERhdGEoY2RzKSRkYXRhc2V0X2JhdGNoCmRmMD1kZjBbaXMuZmluaXRlKGRmMCRwc2V1ZG90aW1lKSxdCmRmMD1kZjBbb3JkZXIoZGYwJHBzZXVkb3RpbWUsZGVjcmVhc2luZyA9IEYpLCxkcm9wPUZdCmRmMCR4PWRmMCRwc2V1ZG90aW1lL21heChkZjAkcHNldWRvdGltZSkKZGZfcHNldWRvdGltZV9saXN0JHJhdz1kZjAKYGBgCgotIEZlYXR1cmUgcGxvdHMgb2YgYEZDR1IzQWAgYW5kIGBTMTAwQThgCgpgYGB7cn0KcD1nZXRfcGxvdDQoZGYwMCA9IGRmMCkKYGBgCgpgYGB7ciBmaWcuaGVpZ2h0PTQsZmlnLndpZHRoPTE4fQpwCmBgYAoKYGBge3J9CmRmX2Rlbj1jb2xEYXRhKGNkcykKdHQxPWtzLnRlc3QoZGZfZGVuJFBzZXVkb3RpbWVbZGZfZGVuJGRhdGFzZXRfYmF0Y2g9PSJUMSJdLGRmX2RlbiRQc2V1ZG90aW1lW2RmX2RlbiRkYXRhc2V0X2JhdGNoPT0iVDMiXSkKdHQxCgp0dDI9a3MudGVzdChkZl9kZW4kUHNldWRvdGltZVtkZl9kZW4kZGF0YXNldF9iYXRjaD09IlQxIl0sZGZfZGVuJFBzZXVkb3RpbWVbZGZfZGVuJGRhdGFzZXRfYmF0Y2g9PSJUMiJdKQp0dDIKCnR0Mz1rcy50ZXN0KGRmX2RlbiRQc2V1ZG90aW1lW2RmX2RlbiRkYXRhc2V0X2JhdGNoPT0iVDIiXSxkZl9kZW4kUHNldWRvdGltZVtkZl9kZW4kZGF0YXNldF9iYXRjaD09IlQzIl0pCnR0MwpgYGAKCmBgYHtyfQpTdGFibGU1WzEsMjo0XT1tYXRyaXgoZ2V0X3BfbmV3KGModHQxJHAudmFsdWUsdHQyJHAudmFsdWUsdHQzJHAudmFsdWUpLGModHQxJHN0YXRpc3RpYyx0dDIkc3RhdGlzdGljLHR0MyRzdGF0aXN0aWMpKSwxLDMpCmBgYAoKIyMgQWxsIGdlbmVzIHJhdyAKYGBge3J9CmNlbGwubWV0YS5kYXRhPW9iajBAbWV0YS5kYXRhCmNlbGwubWV0YS5kYXRhJGRhdGFzZXRfYmF0Y2g9cGx5cjo6bWFwdmFsdWVzKGNlbGwubWV0YS5kYXRhJGJhdGNoX2xhYmVsLG5hbWVzKG1hcHJ1bGVzKSxtYXBydWxlcykKZ2VuZV9hbm49ZGF0YS5mcmFtZShnZW5lX3Nob3J0X25hbWUgPSBtYWtlLnVuaXF1ZShyb3duYW1lcyhyYXcuZGF0YSkpLHJvdy5uYW1lcyA9IG1ha2UudW5pcXVlKHJvd25hbWVzKHJhdy5kYXRhKSkpCiNwZCA8LSBuZXcoIkFubm90YXRlZERhdGFGcmFtZSIsZGF0YT1jZWxsLm1ldGEuZGF0YSkKI2ZkIDwtIG5ldygiQW5ub3RhdGVkRGF0YUZyYW1lIixkYXRhPWdlbmVfYW5uKQpjZHMgPC0gbmV3X2NlbGxfZGF0YV9zZXQocmF3LmRhdGEsIGNlbGxfbWV0YWRhdGEgPSBjZWxsLm1ldGEuZGF0YSxnZW5lX21ldGFkYXRhID1nZW5lX2FubikKIyMgU3RlcCAxOiBOb3JtYWxpemUgYW5kIHByZS1wcm9jZXNzIHRoZSBkYXRhCmNkcyA8LSBwcmVwcm9jZXNzX2NkcyhjZHMsIG51bV9kaW0gPSAzMixtZXRob2Q9IlBDQSIsbm9ybV9tZXRob2Q9ImxvZyIsdmVyYm9zZSA9IEYpCiMjIFN0ZXAgMjogUmVtb3ZlIGJhdGNoIGVmZmVjdHMgd2l0aCBjZWxsIGFsaWdubWVudAojI2NkcyA8LSBhbGlnbl9jZHMoY2RzLCBhbGlnbm1lbnRfZ3JvdXAgPSAiQmF0Y2hJRCIsIHJlc2lkdWFsX21vZGVsX2Zvcm11bGFfc3RyID0gTlVMTCkKIyMgU3RlcCAzOiBSZWR1Y2UgdGhlIGRpbWVuc2lvbnMgdXNpbmcgVU1BUApjZHMgPC0gcmVkdWNlX2RpbWVuc2lvbihjZHMscmVkdWN0aW9uX21ldGhvZCA9ICJVTUFQIixwcmVwcm9jZXNzX21ldGhvZD0iUENBIix2ZXJib3NlID0gRikKCiMjIFN0ZXAgNDogQ2x1c3RlciB0aGUgY2VsbHMKY2RzIDwtIGNsdXN0ZXJfY2VsbHMoY2RzLHJlZHVjdGlvbl9tZXRob2QgPSJVTUFQIixjbHVzdGVyX21ldGhvZCA9ICJsZWlkZW4iLHZlcmJvc2UgPSBGKQojIENvbnN0cnVjdCB0aGUgZ3JhcGgKIyBOb3RlIHRoYXQsIGZvciB0aGUgcmVzdCBvZiB0aGUgY29kZSB0byBydW4sIHRoZSBncmFwaCBzaG91bGQgYmUgZnVsbHkgKHBhcnRpb25seSkgY29ubmVjdGVkCiMjIFN0ZXAgNTogTGVhcm4gYSBncmFwaApjZHMgPC0gbGVhcm5fZ3JhcGgoY2RzLCB1c2VfcGFydGl0aW9uID0gVCx2ZXJib3NlID0gRikKY29sRGF0YShjZHMpJGNsdXN0ZXJzPWNkc0BjbHVzdGVycyRVTUFQJGNsdXN0ZXJzCnAxPXBsb3RfY2VsbHMoY2RzLGNvbG9yX2NlbGxzX2J5ID0gInBhcnRpdGlvbiIsbGFiZWxfY2VsbF9ncm91cHMgPSBGKSt0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIikKcDI9cGxvdF9jZWxscyhjZHMsY29sb3JfY2VsbHNfYnkgPSAiY2x1c3RlcnMiLGxhYmVsX2NlbGxfZ3JvdXBzPUYsZ3JhcGhfbGFiZWxfc2l6ZT0yLCBsYWJlbF9sZWF2ZXM9RixsYWJlbF9icmFuY2hfcG9pbnRzPUYpK3RoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiKQpwPWNvd3Bsb3Q6OnBsb3RfZ3JpZChwMSxwMixhbGlnbiA9ICJoIixuY29sID0gMykKYGBgCgoKYGBge3IsZmlnLmhlaWdodD01LGZpZy53aWR0aD0xOH0KcApgYGAKCmBgYHtyfQojIyBTdGVwIDY6IE9yZGVyIGNlbGxzCiMgYSBoZWxwZXIgZnVuY3Rpb24gdG8gaWRlbnRpZnkgdGhlIHJvb3QgcHJpbmNpcGFsIHBvaW50czoKZ2V0X2VhcmxpZXN0X3ByaW5jaXBhbF9ub2RlIDwtIGZ1bmN0aW9uKGNkcywgY2x1c3Rlcj1jKCIxIiwiNSIpKXsKICByb290X3ByX25vZGVzPXNhcHBseShjbHVzdGVyLGZ1bmN0aW9uKGlpKXsKICAgIGNlbGxfaWRzIDwtIHdoaWNoKGNvbERhdGEoY2RzKVssICJjbHVzdGVycyJdICVpbiVpaSkKICAKICBjbG9zZXN0X3ZlcnRleCA8LWNkc0BwcmluY2lwYWxfZ3JhcGhfYXV4W1siVU1BUCJdXSRwcl9ncmFwaF9jZWxsX3Byb2pfY2xvc2VzdF92ZXJ0ZXgKICAKICBjbG9zZXN0X3ZlcnRleCA8LSBhcy5tYXRyaXgoY2xvc2VzdF92ZXJ0ZXhbY29sbmFtZXMoY2RzKSwgXSkKICByb290X3ByX25vZGVzIDwtaWdyYXBoOjpWKHByaW5jaXBhbF9ncmFwaChjZHMpW1siVU1BUCJdXSkkbmFtZVthcy5udW1lcmljKG5hbWVzKHdoaWNoLm1heCh0YWJsZShjbG9zZXN0X3ZlcnRleFtjZWxsX2lkcyxdKSkpKV0KICB9KQogIHJvb3RfcHJfbm9kZXMKfQojIHJvb3QgY2VsbHMKaWRzPWdldF9lYXJsaWVzdF9wcmluY2lwYWxfbm9kZShjZHMsY2x1c3Rlcj1jKCI0IiwiNSIpKQpjZHMgPC0gb3JkZXJfY2VsbHMoY2RzLHJvb3RfcHJfbm9kZXMgPSBpZHMpCiNwbG90X2NlbGxzKGNkcyxjb2xvcl9jZWxsc19ieSA9ICJwc2V1ZG90aW1lIikKYGBgCgpgYGB7cixmaWcuaGVpZ2h0PTUsZmlnLndpZHRoPTE4fQpjb2xEYXRhKGNkcykkcHNldWRvdGltZT1wc2V1ZG90aW1lKGNkcykKY29sRGF0YShjZHMpJFBzZXVkb3RpbWU9Y29sRGF0YShjZHMpJHBzZXVkb3RpbWUvbWF4KGNvbERhdGEoY2RzKSRwc2V1ZG90aW1lLG5hLnJtID0gVCkKZGZfZGVuPXBEYXRhKGNkcylbLGMoIlBzZXVkb3RpbWUiLCJkYXRhc2V0X2JhdGNoIildCmRmX2Rlbj1hcy5kYXRhLmZyYW1lKGRmX2RlblshaXMuaW5maW5pdGUoZGZfZGVuJFBzZXVkb3RpbWUpLF0pCgpzZXQuc2VlZCgxMCkKdGhlbWVfdXNlPXRoZW1lKGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9MTYpLAogICAgICAgICAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9MjApKQoKcF9vcmlfYWxsXzE9cGxvdF9jZWxscyhjZHMsY29sb3JfY2VsbHNfYnkgPSAiZGF0YXNldF9iYXRjaCIsZ3JhcGhfbGFiZWxfc2l6ZT0wLGFscGhhPTEsY2VsbF9zaXplID0gMC42KSsKICBndWlkZXMoY29sb3VyID0gZ3VpZGVfbGVnZW5kKG92ZXJyaWRlLmFlcyA9IGxpc3QoYWxwaGE9MC43LCBzaXplPTUpKSkrCiAgdGhlbWVfdXNlKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiKSt0aGVtZShsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCiAgICAgICAgICAKcF9vcmlfYWxsXzI9cGxvdF9jZWxscyhjZHMsY29sb3JfY2VsbHNfYnkgPSAiUHNldWRvdGltZSIsbGFiZWxfYnJhbmNoX3BvaW50cz1ULGdyYXBoX2xhYmVsX3NpemU9MixhbHBoYT0xLGNlbGxfc2l6ZSA9IDAuNikrCiAgICAgICAgICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiLAogICAgICAgICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dCh2anVzdCA9IDAuMiksCiAgICAgICAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoYW5nbGU9LTUwICksCiAgICAgICAgICAgICAgICAgIGxlZ2VuZC5rZXkuaGVpZ2h0ID0gdW5pdCgwLjUsImNtIiksCiAgICAgICAgICAgICAgICAgIGxlZ2VuZC5rZXkud2lkdGggPSB1bml0KDEsImNtIikpKwogICAgICAgICAgICBndWlkZXMoY29sb3IgPSBndWlkZV9jb2xvdXJiYXIobGFiZWwucG9zaXRpb24gPSAidG9wIikpK3RoZW1lX3VzZQoKcF9vcmlfYWxsXzM9Z2dwbG90KGRhdGE9ZGZfZGVuKStnZW9tX2RlbnNpdHkoYWVzKHg9UHNldWRvdGltZSxmaWxsPWRhdGFzZXRfYmF0Y2gpLGFscGhhPTAuNykrCiAgICAgICAgICAgIHNjYWxlX3lfY29udGludW91cyhleHBhbmQgPSBjKDAsMCkpKwogICAgICAgICAgICBzY2FsZV94X2NvbnRpbnVvdXMoZXhwYW5kID0gYygwLDApKSsKICAgICAgICAgICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJ0b3AiKSt0aGVtZV91c2UKCnBfbW9ub2NsZV9vcmlfYWxsPWVnZzo6Z2dhcnJhbmdlKHBfb3JpX2FsbF8xLHBfb3JpX2FsbF8yLHBfb3JpX2FsbF8zLG5jb2w9MyxkcmF3PUYpCmBgYAoKYGBge3J9CiMgcHJpbnRlZCBob3cgbWFueSBjZWxscyB3aXRoIG5vIHBzZXVkb3RpbWUKdGFibGUoYXMubnVtZXJpYyhpcy5pbmZpbml0ZShwRGF0YShjZHMpWyxjKCJwc2V1ZG90aW1lIildKSkpICMwIG1lYW4gbm9ybWFsIHBzZXVkb3RpbWUgYW5kIDEgbWVhbnMgaW5maW5pdHkuCmBgYAoKYGBge3IgZmlnLmhlaWdodD01LGZpZy53aWR0aD0xOH0KcF9tb25vY2xlX29yaV9hbGwKYGBgCgpgYGB7cn0KY2RzX2V4cHJzPUZldGNoRGF0YShvYmowLHZhcnMgPSBjKCJGQ0dSM0EiLCJTMTAwQTgiKSkKZGYwPWRhdGEuZnJhbWUoY2JpbmQocHNldWRvdGltZT1wRGF0YShjZHMpJFBzZXVkb3RpbWUsY2RzX2V4cHJzKSkKI2Nkc19leHBycz1hcy5tYXRyaXgoU2luZ2xlQ2VsbEV4cGVyaW1lbnQ6OmNvdW50cyhjZHMpW2MoIkZDR1IzQSIsIlMxMDBBOCIpLF0pCiNkZjA9ZGF0YS5mcmFtZShjYmluZChwc2V1ZG90aW1lPXBEYXRhKGNkcykkUHNldWRvdGltZSxsb2cxcCh0KGNkc19leHBycykvc2l6ZV9mYWN0b3JzKGNkcykpKSkKZGYwJFVNQVBfMT1yZWR1Y2VkRGltcyhjZHMpJFVNQVBbLDFdCmRmMCRVTUFQXzI9cmVkdWNlZERpbXMoY2RzKSRVTUFQWywyXQpkZjAkQmF0Y2hJRD1wRGF0YShjZHMpJGRhdGFzZXRfYmF0Y2gKZGYwPWRmMFtpcy5maW5pdGUoZGYwJHBzZXVkb3RpbWUpLF0KZGYwPWRmMFtvcmRlcihkZjAkcHNldWRvdGltZSxkZWNyZWFzaW5nID0gRiksLGRyb3A9Rl0KZGYwJHg9ZGYwJHBzZXVkb3RpbWUvbWF4KGRmMCRwc2V1ZG90aW1lKQpkZl9wc2V1ZG90aW1lX2xpc3QkcmF3X2FsbD1kZjAKYGBgCgotIEZlYXR1cmUgcGxvdHMgb2YgYEZDR1IzQWAgYW5kIGBTMTAwQThgCgpgYGB7cn0KcD1nZXRfcGxvdDQoZGYwMCA9IGRmMCkKYGBgCgpgYGB7cixmaWcuaGVpZ2h0PTQsZmlnLndpZHRoPTE4fQpwCmBgYAoKYGBge3J9CmRmX2Rlbj1jb2xEYXRhKGNkcykKdHQxPWtzLnRlc3QoZGZfZGVuJFBzZXVkb3RpbWVbZGZfZGVuJGRhdGFzZXRfYmF0Y2g9PSJUMSJdLGRmX2RlbiRQc2V1ZG90aW1lW2RmX2RlbiRkYXRhc2V0X2JhdGNoPT0iVDMiXSkKdHQxCnR0Mj1rcy50ZXN0KGRmX2RlbiRQc2V1ZG90aW1lW2RmX2RlbiRkYXRhc2V0X2JhdGNoPT0iVDEiXSxkZl9kZW4kUHNldWRvdGltZVtkZl9kZW4kZGF0YXNldF9iYXRjaD09IlQyIl0pCnR0Mgp0dDM9a3MudGVzdChkZl9kZW4kUHNldWRvdGltZVtkZl9kZW4kZGF0YXNldF9iYXRjaD09IlQyIl0sZGZfZGVuJFBzZXVkb3RpbWVbZGZfZGVuJGRhdGFzZXRfYmF0Y2g9PSJUMyJdKQp0dDMKYGBgCgpgYGB7cn0KU3RhYmxlNVsyLDI6NF09bWF0cml4KGdldF9wX25ldyhjKHR0MSRwLnZhbHVlLHR0MiRwLnZhbHVlLHR0MyRwLnZhbHVlKSxjKHR0MSRzdGF0aXN0aWMsdHQyJHN0YXRpc3RpYyx0dDMkc3RhdGlzdGljKSksMSwzKQpgYGAKCiMgTW9ub2NsZTMgdXNpbmcgY2FyREVDCgpJbiB0aGlzIHNlY3Rpb24sIHdlIHdpbGwgZXZhbHV0YXRlIHRoZSBwZXJmb3JtYW5jZSBvZiBjYXJERUMuIAoKTm90ZSB0aGF0OiBjYXJERUMgdXNlZCBhbGwgZ2VuZXMgYW5kIGV4dHJhY3RlZCBIVkcgdG8gZXZhbHVhdGUuCgpgYGB7cn0KYWRhdGE9YWQkcmVhZF9oNWFkKCIuLi9maW5hbF9wcm9jZXNzZWRfcmVzdWx0cy9DYXJERUMgUmVzdWx0cy9hZGF0YV9DYXJERUMuaDVhZCIpCmBgYAoKYGBge3J9CmNlbGwubWV0YS5kYXRhPXB5X3RvX3IoYWRhdGEkb2JzKQpjZWxsLm1ldGEuZGF0YSRkYXRhc2V0X2JhdGNoPXBseXI6Om1hcHZhbHVlcyhjZWxsLm1ldGEuZGF0YSRiYXRjaF9sYWJlbCxuYW1lcyhtYXBydWxlcyksbWFwcnVsZXMpCmdlbmVfYW5uMD1weV90b19yKGFkYXRhJHZhcikKZ2VuZV9hbm49ZGF0YS5mcmFtZShnZW5lX3Nob3J0X25hbWUgPSBtYWtlLnVuaXF1ZShyb3duYW1lcyhnZW5lX2FubjApKSwKICAgICAgICAgICAgICAgICAgICBWYXJpYW5jZVR5cGU9Z2VuZV9hbm4wJGBWYXJpYW5jZSBUeXBlYCwKICAgICAgICAgICAgICAgICAgICByb3cubmFtZXMgPSBtYWtlLnVuaXF1ZShyb3duYW1lcyhnZW5lX2FubjApKSkKbXR4PXQocHlfdG9fcihhZGF0YSRsYXllcnNbJ2Rlbm9pc2VkIGNvdW50cyddKSkKY29sbmFtZXMobXR4KT1jZWxsLm1ldGEuZGF0YSRjZWxsbmFtZQpyb3duYW1lcyhtdHgpPXJvd25hbWVzKGdlbmVfYW5uKQptdHhfc2l6ZWZhY3Rvcj0xZTQvY29sU3VtcyhtdHgpCmBgYAoKCiMjIFVzaW5nIGxhdGVudCAKCmBgYHtyfQpjZHMgPC0gbmV3X2NlbGxfZGF0YV9zZXQobXR4LCBjZWxsX21ldGFkYXRhID0gY2VsbC5tZXRhLmRhdGEsZ2VuZV9tZXRhZGF0YSA9Z2VuZV9hbm4pCiMjIFN0ZXAgMTogTm9ybWFsaXplIGFuZCBwcmUtcHJvY2VzcyB0aGUgZGF0YQpjZHMgPC0gcHJlcHJvY2Vzc19jZHMoY2RzLCBudW1fZGltID0gMzIsbWV0aG9kPSJQQ0EiLG5vcm1fbWV0aG9kPSJsb2ciLHZlcmJvc2UgPSBGKQoKdG1wMD1weV90b19yKGFkYXRhJG9ic21bImVtYmVkZGluZyJdKQpjb2xuYW1lcyh0bXAwKT1wYXN0ZTAoIlBDIiwxOm5jb2wodG1wMCkpCnJlZHVjZWREaW1zKGNkcykkUENBPXRtcDAKCiMjIFN0ZXAgMjogUmVtb3ZlIGJhdGNoIGVmZmVjdHMgd2l0aCBjZWxsIGFsaWdubWVudAojI2NkcyA8LSBhbGlnbl9jZHMoY2RzLCBhbGlnbm1lbnRfZ3JvdXAgPSAiQmF0Y2hJRCIsIHJlc2lkdWFsX21vZGVsX2Zvcm11bGFfc3RyID0gTlVMTCkKIyMgU3RlcCAzOiBSZWR1Y2UgdGhlIGRpbWVuc2lvbnMgdXNpbmcgVU1BUApjZHMgPC0gcmVkdWNlX2RpbWVuc2lvbihjZHMscmVkdWN0aW9uX21ldGhvZCA9ICJVTUFQIixwcmVwcm9jZXNzX21ldGhvZD0iUENBIix2ZXJib3NlID0gRikKCiMjIFN0ZXAgNDogQ2x1c3RlciB0aGUgY2VsbHMKY2RzIDwtIGNsdXN0ZXJfY2VsbHMoY2RzLHJlZHVjdGlvbl9tZXRob2QgPSJVTUFQIixjbHVzdGVyX21ldGhvZCA9ICJsZWlkZW4iLHZlcmJvc2UgPSBGKQoKIyBDb25zdHJ1Y3QgdGhlIGdyYXBoCiMgTm90ZSB0aGF0LCBmb3IgdGhlIHJlc3Qgb2YgdGhlIGNvZGUgdG8gcnVuLCB0aGUgZ3JhcGggc2hvdWxkIGJlIGZ1bGx5IChwYXJ0aW9ubHkpIGNvbm5lY3RlZAojIyBTdGVwIDU6IExlYXJuIGEgZ3JhcGgKY2RzIDwtIGxlYXJuX2dyYXBoKGNkcywgdXNlX3BhcnRpdGlvbiA9IFQsdmVyYm9zZSA9IEYpCmNvbERhdGEoY2RzKSRjbHVzdGVycz1jZHNAY2x1c3RlcnMkVU1BUCRjbHVzdGVycwpwMT1wbG90X2NlbGxzKGNkcyxjb2xvcl9jZWxsc19ieSA9ICJwYXJ0aXRpb24iLGxhYmVsX2NlbGxfZ3JvdXBzID0gRikrdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIpCnAyPXBsb3RfY2VsbHMoY2RzLGNvbG9yX2NlbGxzX2J5ID0gImNsdXN0ZXJzIixsYWJlbF9jZWxsX2dyb3Vwcz1GLGdyYXBoX2xhYmVsX3NpemU9MiwgbGFiZWxfbGVhdmVzPUYsbGFiZWxfYnJhbmNoX3BvaW50cz1GKSt0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIikKcD1jb3dwbG90OjpwbG90X2dyaWQocDEscDIsYWxpZ24gPSAiaCIsbmNvbCA9IDMpCmBgYAoKYGBge3IsIGZpZy5oZWlnaHQ9NSxmaWcud2lkdGg9MTh9CnAKYGBgCgpgYGB7cn0KIyMgU3RlcCA2OiBPcmRlciBjZWxscwojIHJvb3QgY2VsbHMKaWRzPWdldF9lYXJsaWVzdF9wcmluY2lwYWxfbm9kZShjZHMsY2x1c3Rlcj1jKCIzIikpCmNkcyA8LSBvcmRlcl9jZWxscyhjZHMsIHJvb3RfcHJfbm9kZXM9aWRzKQpwbG90X2NlbGxzKGNkcyxjb2xvcl9jZWxsc19ieSA9ICJwc2V1ZG90aW1lIikKYGBgCgoKYGBge3IsZmlnLmhlaWdodD01LGZpZy53aWR0aD0xOH0KY29sRGF0YShjZHMpJHBzZXVkb3RpbWU9cHNldWRvdGltZShjZHMpCmNvbERhdGEoY2RzKSRQc2V1ZG90aW1lPWNvbERhdGEoY2RzKSRwc2V1ZG90aW1lL21heChjb2xEYXRhKGNkcykkcHNldWRvdGltZSxuYS5ybSA9IFQpCmRmX2Rlbj1wRGF0YShjZHMpWyxjKCJQc2V1ZG90aW1lIiwiZGF0YXNldF9iYXRjaCIpXQpkZl9kZW49YXMuZGF0YS5mcmFtZShkZl9kZW5bIWlzLmluZmluaXRlKGRmX2RlbiRQc2V1ZG90aW1lKSxdKQpzZXQuc2VlZCgxMCkKCnRoZW1lX3VzZT10aGVtZShsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTE2KSwKICAgICAgICAgICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTIwKSkKCnBfY2FyREVDX2xhdGVudF8xPXBsb3RfY2VsbHMoY2RzLGNvbG9yX2NlbGxzX2J5ID0gImRhdGFzZXRfYmF0Y2giLCxncmFwaF9sYWJlbF9zaXplPTAsYWxwaGE9MSxjZWxsX3NpemUgPSAwLjYpKwogIGd1aWRlcyhjb2xvdXIgPSBndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID0gbGlzdChhbHBoYT0wLjcsIHNpemU9NSkpKSsKICB0aGVtZV91c2UrCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIpCiAgICAgICAgICAKcF9jYXJERUNfbGF0ZW50XzI9cGxvdF9jZWxscyhjZHMsY29sb3JfY2VsbHNfYnkgPSAiUHNldWRvdGltZSIsbGFiZWxfYnJhbmNoX3BvaW50cz1ULGdyYXBoX2xhYmVsX3NpemU9MixhbHBoYT0xLGNlbGxfc2l6ZSA9IDAuNikrCiAgICAgICAgICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiLAogICAgICAgICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dCh2anVzdCA9IDAuMiksCiAgICAgICAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoYW5nbGU9LTUwICksCiAgICAgICAgICAgICAgICAgIGxlZ2VuZC5rZXkuaGVpZ2h0ID0gdW5pdCgwLjUsImNtIiksCiAgICAgICAgICAgICAgICAgIGxlZ2VuZC5rZXkud2lkdGggPSB1bml0KDEsImNtIikpKwogICAgICAgICAgICBndWlkZXMoY29sb3IgPSBndWlkZV9jb2xvdXJiYXIobGFiZWwucG9zaXRpb24gPSAidG9wIikpK3RoZW1lX3VzZQoKcF9jYXJERUNfbGF0ZW50XzM9Z2dwbG90KGRhdGE9ZGZfZGVuKStnZW9tX2RlbnNpdHkoYWVzKHg9UHNldWRvdGltZSxmaWxsPWRhdGFzZXRfYmF0Y2gpLGFscGhhPTAuNykrCiAgICAgICAgICAgIHNjYWxlX3lfY29udGludW91cyhleHBhbmQgPSBjKDAsMCkpKwogICAgICAgICAgICBzY2FsZV94X2NvbnRpbnVvdXMoZXhwYW5kID0gYygwLDApKSsKICAgICAgICAgICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJ0b3AiKSt0aGVtZV91c2UKCnBfbW9ub2NsZV9jYXJERUNfbGF0ZW50PWVnZzo6Z2dhcnJhbmdlKHBfY2FyREVDX2xhdGVudF8xLHBfY2FyREVDX2xhdGVudF8yLHBfY2FyREVDX2xhdGVudF8zLG5jb2w9MyxkcmF3PUYpCmBgYAoKCmBgYHtyLCBmaWcuaGVpZ2h0PTUsZmlnLndpZHRoPTE4fQpwX21vbm9jbGVfY2FyREVDX2xhdGVudApgYGAKCmBgYHtyfQojY2RzX2V4cHJzPUZldGNoRGF0YShvYmowLHZhcnMgPSBjKCJGQ0dSM0EiLCJTMTAwQTgiKSkKI2RmMD1kYXRhLmZyYW1lKGNiaW5kKHBzZXVkb3RpbWU9cERhdGEoY2RzKSRQc2V1ZG90aW1lLGNkc19leHBycykpPTFlNC9yb3dTdW1zKG10eCkKY2RzX2V4cHJzPWFzLm1hdHJpeChTaW5nbGVDZWxsRXhwZXJpbWVudDo6Y291bnRzKGNkcylbYygiRkNHUjNBIiwiUzEwMEE4IiksXSkKZGYwPWRhdGEuZnJhbWUoY2JpbmQocHNldWRvdGltZT1wRGF0YShjZHMpJFBzZXVkb3RpbWUsbG9nMXAodChjZHNfZXhwcnMpKm10eF9zaXplZmFjdG9yKSkpCmRmMCRVTUFQXzE9cmVkdWNlZERpbXMoY2RzKSRVTUFQWywxXQpkZjAkVU1BUF8yPXJlZHVjZWREaW1zKGNkcykkVU1BUFssMl0KZGYwJEJhdGNoSUQ9cERhdGEoY2RzKSRkYXRhc2V0X2JhdGNoCmRmMD1kZjBbaXMuZmluaXRlKGRmMCRwc2V1ZG90aW1lKSxdCmRmMD1kZjBbb3JkZXIoZGYwJHBzZXVkb3RpbWUsZGVjcmVhc2luZyA9IEYpLCxkcm9wPUZdCmRmMCR4PWRmMCRwc2V1ZG90aW1lL21heChkZjAkcHNldWRvdGltZSkKZGZfcHNldWRvdGltZV9saXN0JGNhckRFQ19sYXRlbnQ9ZGYwCmBgYAoKCi0gRmVhdHVyZSBwbG90cyBvZiBgRkNHUjNBYCBhbmQgYFMxMDBBOGAKCmBgYHtyfQpwPWdldF9wbG90NChkZjAwID0gZGYwKQpgYGAKCmBgYHtyLCBmaWcuaGVpZ2h0PTQsZmlnLndpZHRoPTE4fQpwCmBgYAoKYGBge3J9CmRmX2Rlbj1jb2xEYXRhKGNkcykKdHQxPWtzLnRlc3QoZGZfZGVuJFBzZXVkb3RpbWVbZGZfZGVuJGRhdGFzZXRfYmF0Y2g9PSJUMSJdLGRmX2RlbiRQc2V1ZG90aW1lW2RmX2RlbiRkYXRhc2V0X2JhdGNoPT0iVDMiXSkKdHQxCnR0Mj1rcy50ZXN0KGRmX2RlbiRQc2V1ZG90aW1lW2RmX2RlbiRkYXRhc2V0X2JhdGNoPT0iVDEiXSxkZl9kZW4kUHNldWRvdGltZVtkZl9kZW4kZGF0YXNldF9iYXRjaD09IlQyIl0pCnR0Mgp0dDM9a3MudGVzdChkZl9kZW4kUHNldWRvdGltZVtkZl9kZW4kZGF0YXNldF9iYXRjaD09IlQyIl0sZGZfZGVuJFBzZXVkb3RpbWVbZGZfZGVuJGRhdGFzZXRfYmF0Y2g9PSJUMyJdKQp0dDMKYGBgCgpgYGB7cn0KU3RhYmxlNVszLDI6NF09bWF0cml4KGdldF9wX25ldyhjKHR0MSRwLnZhbHVlLHR0MiRwLnZhbHVlLHR0MyRwLnZhbHVlKSxjKHR0MSRzdGF0aXN0aWMsdHQyJHN0YXRpc3RpYyx0dDMkc3RhdGlzdGljKSksMSwzKQpgYGAKCgojIyBIVkdzIGRlbm9pc2VkCgpgYGB7cn0KY2RzIDwtIG5ld19jZWxsX2RhdGFfc2V0KG10eFtnZW5lX2FubiRWYXJpYW5jZVR5cGU9PSJIVkciLF0sIGNlbGxfbWV0YWRhdGEgPSBjZWxsLm1ldGEuZGF0YSxnZW5lX21ldGFkYXRhID1nZW5lX2FubltnZW5lX2FubiRWYXJpYW5jZVR5cGU9PSJIVkciLCxkcm9wPUZdKQojIyBTdGVwIDE6IE5vcm1hbGl6ZSBhbmQgcHJlLXByb2Nlc3MgdGhlIGRhdGEKY2RzIDwtIHByZXByb2Nlc3NfY2RzKGNkcywgbnVtX2RpbSA9IDMyLG1ldGhvZD0iUENBIixub3JtX21ldGhvZD0ibG9nIikKCiMjIFN0ZXAgMjogUmVtb3ZlIGJhdGNoIGVmZmVjdHMgd2l0aCBjZWxsIGFsaWdubWVudAojI2NkcyA8LSBhbGlnbl9jZHMoY2RzLCBhbGlnbm1lbnRfZ3JvdXAgPSAiQmF0Y2hJRCIsIHJlc2lkdWFsX21vZGVsX2Zvcm11bGFfc3RyID0gTlVMTCkKIyMgU3RlcCAzOiBSZWR1Y2UgdGhlIGRpbWVuc2lvbnMgdXNpbmcgVU1BUApjZHMgPC0gcmVkdWNlX2RpbWVuc2lvbihjZHMscmVkdWN0aW9uX21ldGhvZCA9ICJVTUFQIixwcmVwcm9jZXNzX21ldGhvZD0iUENBIix2ZXJib3NlID0gRikKCiMjIFN0ZXAgNDogQ2x1c3RlciB0aGUgY2VsbHMKY2RzIDwtIGNsdXN0ZXJfY2VsbHMoY2RzLHJlZHVjdGlvbl9tZXRob2QgPSJVTUFQIixjbHVzdGVyX21ldGhvZCA9ICJsZWlkZW4iLHZlcmJvc2UgPSBGKQoKIyBDb25zdHJ1Y3QgdGhlIGdyYXBoCiMgTm90ZSB0aGF0LCBmb3IgdGhlIHJlc3Qgb2YgdGhlIGNvZGUgdG8gcnVuLCB0aGUgZ3JhcGggc2hvdWxkIGJlIGZ1bGx5IChwYXJ0aW9ubHkpIGNvbm5lY3RlZAojIyBTdGVwIDU6IExlYXJuIGEgZ3JhcGgKY2RzIDwtIGxlYXJuX2dyYXBoKGNkcywgdXNlX3BhcnRpdGlvbiA9IFQsdmVyYm9zZSA9IEYpCmNvbERhdGEoY2RzKSRjbHVzdGVycz1jZHNAY2x1c3RlcnMkVU1BUCRjbHVzdGVycwpwMT1wbG90X2NlbGxzKGNkcyxjb2xvcl9jZWxsc19ieSA9ICJwYXJ0aXRpb24iLGxhYmVsX2NlbGxfZ3JvdXBzID0gRikrdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIpCnAyPXBsb3RfY2VsbHMoY2RzLGNvbG9yX2NlbGxzX2J5ID0gImNsdXN0ZXJzIixsYWJlbF9jZWxsX2dyb3Vwcz1GLGdyYXBoX2xhYmVsX3NpemU9MiwgbGFiZWxfbGVhdmVzPUYsbGFiZWxfYnJhbmNoX3BvaW50cz1GKSt0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIikKcD1jb3dwbG90OjpwbG90X2dyaWQocDEscDIsYWxpZ24gPSAiaCIsbmNvbCA9IDMpCmBgYAoKYGBge3IgZmlnLmhlaWdodD01LGZpZy53aWR0aD0xOH0KcApgYGAKCmBgYHtyfQojIyBTdGVwIDY6IE9yZGVyIGNlbGxzCiMgcm9vdCBjZWxscwppZHM9Z2V0X2VhcmxpZXN0X3ByaW5jaXBhbF9ub2RlKGNkcyxjbHVzdGVyPWMoIjQiKSkKY2RzIDwtIG9yZGVyX2NlbGxzKGNkcywgcm9vdF9wcl9ub2Rlcz1pZHMpCiNwbG90X2NlbGxzKGNkcyxjb2xvcl9jZWxsc19ieSA9ICJwc2V1ZG90aW1lIikKYGBgCgoKYGBge3IsZmlnLmhlaWdodD01LGZpZy53aWR0aD0xOH0KY29sRGF0YShjZHMpJHBzZXVkb3RpbWU9cHNldWRvdGltZShjZHMpCmNvbERhdGEoY2RzKSRQc2V1ZG90aW1lPWNvbERhdGEoY2RzKSRwc2V1ZG90aW1lL21heChjb2xEYXRhKGNkcykkcHNldWRvdGltZSxuYS5ybSA9IFQpCmRmX2Rlbj1wRGF0YShjZHMpWyxjKCJQc2V1ZG90aW1lIiwiZGF0YXNldF9iYXRjaCIpXQpkZl9kZW49YXMuZGF0YS5mcmFtZShkZl9kZW5bIWlzLmluZmluaXRlKGRmX2RlbiRQc2V1ZG90aW1lKSxdKQpzZXQuc2VlZCgxMCkKCnRoZW1lX3VzZT10aGVtZShsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTE2KSwKICAgICAgICAgICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTIwKSkKCnBfY2FyREVDX2Rlbm9pc2VkX2h2Z18xID0gcGxvdF9jZWxscyhjZHMsY29sb3JfY2VsbHNfYnkgPSAiZGF0YXNldF9iYXRjaCIsLGdyYXBoX2xhYmVsX3NpemU9MCxhbHBoYT0xLGNlbGxfc2l6ZSA9IDAuNikrCiAgZ3VpZGVzKGNvbG91ciA9IGd1aWRlX2xlZ2VuZChvdmVycmlkZS5hZXMgPSBsaXN0KGFscGhhPTAuNywgc2l6ZT01KSkpKwogIHRoZW1lX3VzZSsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIikKICAgICAgICAgIApwX2NhckRFQ19kZW5vaXNlZF9odmdfMj1wbG90X2NlbGxzKGNkcyxjb2xvcl9jZWxsc19ieSA9ICJQc2V1ZG90aW1lIixsYWJlbF9icmFuY2hfcG9pbnRzPVQsZ3JhcGhfbGFiZWxfc2l6ZT0yLGFscGhhPTEsY2VsbF9zaXplID0gMC42KSsKICAgICAgICAgICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIsCiAgICAgICAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHZqdXN0ID0gMC4yKSwKICAgICAgICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChhbmdsZT0tNTAgKSwKICAgICAgICAgICAgICAgICAgbGVnZW5kLmtleS5oZWlnaHQgPSB1bml0KDAuNSwiY20iKSwKICAgICAgICAgICAgICAgICAgbGVnZW5kLmtleS53aWR0aCA9IHVuaXQoMSwiY20iKSkrCiAgICAgICAgICAgIGd1aWRlcyhjb2xvciA9IGd1aWRlX2NvbG91cmJhcihsYWJlbC5wb3NpdGlvbiA9ICJ0b3AiKSkrdGhlbWVfdXNlCgpwX2NhckRFQ19kZW5vaXNlZF9odmdfMz1nZ3Bsb3QoZGF0YT1kZl9kZW4pK2dlb21fZGVuc2l0eShhZXMoeD1Qc2V1ZG90aW1lLGZpbGw9ZGF0YXNldF9iYXRjaCksYWxwaGE9MC43KSsKICAgICAgICAgICAgc2NhbGVfeV9jb250aW51b3VzKGV4cGFuZCA9IGMoMCwwKSkrCiAgICAgICAgICAgIHNjYWxlX3hfY29udGludW91cyhleHBhbmQgPSBjKDAsMCkpKwogICAgICAgICAgICB0aGVtZShsZWdlbmQucG9zaXRpb249InRvcCIpK3RoZW1lX3VzZQoKcF9tb25vY2xlX2NhckRFQ19kZW5vaXNlZF9odmc9ZWdnOjpnZ2FycmFuZ2UocF9jYXJERUNfZGVub2lzZWRfaHZnXzEscF9jYXJERUNfZGVub2lzZWRfaHZnXzIscF9jYXJERUNfZGVub2lzZWRfaHZnXzMsbmNvbD0zLGRyYXc9RikKYGBgCgoKYGBge3IsIGZpZy5oZWlnaHQ9NSxmaWcud2lkdGg9MTh9CnBfbW9ub2NsZV9jYXJERUNfZGVub2lzZWRfaHZnCmBgYAoKCmBgYHtyfQojY2RzX2V4cHJzPUZldGNoRGF0YShvYmowLHZhcnMgPSBjKCJGQ0dSM0EiLCJTMTAwQTgiKSkKI2RmMD1kYXRhLmZyYW1lKGNiaW5kKHBzZXVkb3RpbWU9cERhdGEoY2RzKSRQc2V1ZG90aW1lLGNkc19leHBycykpCmNkc19leHBycz1hcy5tYXRyaXgoU2luZ2xlQ2VsbEV4cGVyaW1lbnQ6OmNvdW50cyhjZHMpW2MoIkZDR1IzQSIsIlMxMDBBOCIpLF0pCmRmMD1kYXRhLmZyYW1lKGNiaW5kKHBzZXVkb3RpbWU9cERhdGEoY2RzKSRQc2V1ZG90aW1lLGxvZzFwKHQoY2RzX2V4cHJzKSptdHhfc2l6ZWZhY3RvcikpKQpkZjAkVU1BUF8xPXJlZHVjZWREaW1zKGNkcykkVU1BUFssMV0KZGYwJFVNQVBfMj1yZWR1Y2VkRGltcyhjZHMpJFVNQVBbLDJdCmRmMCRCYXRjaElEPXBEYXRhKGNkcykkZGF0YXNldF9iYXRjaApkZjA9ZGYwW2lzLmZpbml0ZShkZjAkcHNldWRvdGltZSksXQpkZjA9ZGYwW29yZGVyKGRmMCRwc2V1ZG90aW1lLGRlY3JlYXNpbmcgPSBGKSwsZHJvcD1GXQpkZjAkeD1kZjAkcHNldWRvdGltZS9tYXgoZGYwJHBzZXVkb3RpbWUpCmRmX3BzZXVkb3RpbWVfbGlzdCRjYXJERUNfZGVub2lzZWRfaHZnPWRmMApgYGAKCi0gRmVhdHVyZSBwbG90cyBvZiBgRkNHUjNBYCBhbmQgYFMxMDBBOGAKCmBgYHtyfQpwPWdldF9wbG90NChkZjAwID0gZGYwKQpgYGAKCmBgYHtyLCBmaWcuaGVpZ2h0PTQsZmlnLndpZHRoPTE4fQpwCmBgYAoKYGBge3J9CmRmX2Rlbj1jb2xEYXRhKGNkcykKdHQxPWtzLnRlc3QoZGZfZGVuJFBzZXVkb3RpbWVbZGZfZGVuJGRhdGFzZXRfYmF0Y2g9PSJUMSJdLGRmX2RlbiRQc2V1ZG90aW1lW2RmX2RlbiRkYXRhc2V0X2JhdGNoPT0iVDMiXSkKdHQxCnR0Mj1rcy50ZXN0KGRmX2RlbiRQc2V1ZG90aW1lW2RmX2RlbiRkYXRhc2V0X2JhdGNoPT0iVDEiXSxkZl9kZW4kUHNldWRvdGltZVtkZl9kZW4kZGF0YXNldF9iYXRjaD09IlQyIl0pCnR0Mgp0dDM9a3MudGVzdChkZl9kZW4kUHNldWRvdGltZVtkZl9kZW4kZGF0YXNldF9iYXRjaD09IlQyIl0sZGZfZGVuJFBzZXVkb3RpbWVbZGZfZGVuJGRhdGFzZXRfYmF0Y2g9PSJUMyJdKQp0dDMKYGBgCgpgYGB7cn0KU3RhYmxlNVs0LDI6NF09bWF0cml4KGdldF9wX25ldyhjKHR0MSRwLnZhbHVlLHR0MiRwLnZhbHVlLHR0MyRwLnZhbHVlKSxjKHR0MSRzdGF0aXN0aWMsdHQyJHN0YXRpc3RpYyx0dDMkc3RhdGlzdGljKSksMSwzKQpgYGAKCiMjIEFsbCBnZW5lcyBkZW5vaXNlZAoKYGBge3J9CmNkcyA8LSBuZXdfY2VsbF9kYXRhX3NldChtdHgsIGNlbGxfbWV0YWRhdGEgPSBjZWxsLm1ldGEuZGF0YSxnZW5lX21ldGFkYXRhID1nZW5lX2FubikKIyMgU3RlcCAxOiBOb3JtYWxpemUgYW5kIHByZS1wcm9jZXNzIHRoZSBkYXRhCmNkcyA8LSBwcmVwcm9jZXNzX2NkcyhjZHMsIG51bV9kaW0gPSAzMixtZXRob2Q9IlBDQSIsbm9ybV9tZXRob2Q9ImxvZyIsdmVyYm9zZSA9IEYpCgojIyBTdGVwIDI6IFJlbW92ZSBiYXRjaCBlZmZlY3RzIHdpdGggY2VsbCBhbGlnbm1lbnQKIyNjZHMgPC0gYWxpZ25fY2RzKGNkcywgYWxpZ25tZW50X2dyb3VwID0gIkJhdGNoSUQiLCByZXNpZHVhbF9tb2RlbF9mb3JtdWxhX3N0ciA9IE5VTEwpCiMjIFN0ZXAgMzogUmVkdWNlIHRoZSBkaW1lbnNpb25zIHVzaW5nIFVNQVAKY2RzIDwtIHJlZHVjZV9kaW1lbnNpb24oY2RzLHJlZHVjdGlvbl9tZXRob2QgPSAiVU1BUCIscHJlcHJvY2Vzc19tZXRob2Q9IlBDQSIsdmVyYm9zZSA9IEYpCgojIyBTdGVwIDQ6IENsdXN0ZXIgdGhlIGNlbGxzCmNkcyA8LSBjbHVzdGVyX2NlbGxzKGNkcyxyZWR1Y3Rpb25fbWV0aG9kID0iVU1BUCIsY2x1c3Rlcl9tZXRob2QgPSAibGVpZGVuIix2ZXJib3NlID0gRikKCiMgQ29uc3RydWN0IHRoZSBncmFwaAojIE5vdGUgdGhhdCwgZm9yIHRoZSByZXN0IG9mIHRoZSBjb2RlIHRvIHJ1biwgdGhlIGdyYXBoIHNob3VsZCBiZSBmdWxseSAocGFydGlvbmx5KSBjb25uZWN0ZWQKIyMgU3RlcCA1OiBMZWFybiBhIGdyYXBoCmNkcyA8LSBsZWFybl9ncmFwaChjZHMsIHVzZV9wYXJ0aXRpb24gPSBULHZlcmJvc2UgPSBGKQpjb2xEYXRhKGNkcykkY2x1c3RlcnM9Y2RzQGNsdXN0ZXJzJFVNQVAkY2x1c3RlcnMKcDE9cGxvdF9jZWxscyhjZHMsY29sb3JfY2VsbHNfYnkgPSAicGFydGl0aW9uIixsYWJlbF9jZWxsX2dyb3VwcyA9IEYpK3RoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiKQpwMj1wbG90X2NlbGxzKGNkcyxjb2xvcl9jZWxsc19ieSA9ICJjbHVzdGVycyIsbGFiZWxfY2VsbF9ncm91cHM9RixncmFwaF9sYWJlbF9zaXplPTIsIGxhYmVsX2xlYXZlcz1GLGxhYmVsX2JyYW5jaF9wb2ludHM9RikrdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIpCnA9Y293cGxvdDo6cGxvdF9ncmlkKHAxLHAyLGFsaWduID0gImgiLG5jb2wgPSAzKQpgYGAKCmBgYHtyLCBmaWcuaGVpZ2h0PTUsZmlnLndpZHRoPTE4fQpwCmBgYAoKYGBge3J9CiMjIFN0ZXAgNjogT3JkZXIgY2VsbHMKIyByb290IGNlbGxzCmlkcz1nZXRfZWFybGllc3RfcHJpbmNpcGFsX25vZGUoY2RzLGNsdXN0ZXI9YygiNCIpKQpjZHMgPC0gb3JkZXJfY2VsbHMoY2RzLCByb290X3ByX25vZGVzPWlkcykKI3Bsb3RfY2VsbHMoY2RzLGNvbG9yX2NlbGxzX2J5ID0gInBzZXVkb3RpbWUiKQpgYGAKCmBgYHtyLGZpZy5oZWlnaHQ9NSxmaWcud2lkdGg9MTh9CmNvbERhdGEoY2RzKSRwc2V1ZG90aW1lPXBzZXVkb3RpbWUoY2RzKQpjb2xEYXRhKGNkcykkUHNldWRvdGltZT1jb2xEYXRhKGNkcykkcHNldWRvdGltZS9tYXgoY29sRGF0YShjZHMpJHBzZXVkb3RpbWUsbmEucm0gPSBUKQpkZl9kZW49cERhdGEoY2RzKVssYygiUHNldWRvdGltZSIsImRhdGFzZXRfYmF0Y2giKV0KZGZfZGVuPWFzLmRhdGEuZnJhbWUoZGZfZGVuWyFpcy5pbmZpbml0ZShkZl9kZW4kUHNldWRvdGltZSksXSkKc2V0LnNlZWQoMTApCgp0aGVtZV91c2U9dGhlbWUobGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT0xNiksCiAgICAgICAgICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT0yMCkpCgpwX2NhckRFQ19kZW5vaXNlZF9hbGxfMT1wbG90X2NlbGxzKGNkcyxjb2xvcl9jZWxsc19ieSA9ICJkYXRhc2V0X2JhdGNoIiwsZ3JhcGhfbGFiZWxfc2l6ZT0wLGFscGhhPTEsY2VsbF9zaXplID0gMC42KSsKICBndWlkZXMoY29sb3VyID0gZ3VpZGVfbGVnZW5kKG92ZXJyaWRlLmFlcyA9IGxpc3QoYWxwaGE9MC43LCBzaXplPTUpKSkrCiAgdGhlbWVfdXNlKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiKQogICAgICAgICAgCnBfY2FyREVDX2Rlbm9pc2VkX2FsbF8yPXBsb3RfY2VsbHMoY2RzLGNvbG9yX2NlbGxzX2J5ID0gIlBzZXVkb3RpbWUiLGxhYmVsX2JyYW5jaF9wb2ludHM9VCxncmFwaF9sYWJlbF9zaXplPTIsYWxwaGE9MSxjZWxsX3NpemUgPSAwLjYpKwogICAgICAgICAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIiwKICAgICAgICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQodmp1c3QgPSAwLjIpLAogICAgICAgICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KGFuZ2xlPS01MCApLAogICAgICAgICAgICAgICAgICBsZWdlbmQua2V5LmhlaWdodCA9IHVuaXQoMC41LCJjbSIpLAogICAgICAgICAgICAgICAgICBsZWdlbmQua2V5LndpZHRoID0gdW5pdCgxLCJjbSIpKSsKICAgICAgICAgICAgZ3VpZGVzKGNvbG9yID0gZ3VpZGVfY29sb3VyYmFyKGxhYmVsLnBvc2l0aW9uID0gInRvcCIpKSt0aGVtZV91c2UKCnBfY2FyREVDX2Rlbm9pc2VkX2FsbF8zPWdncGxvdChkYXRhPWRmX2RlbikrZ2VvbV9kZW5zaXR5KGFlcyh4PVBzZXVkb3RpbWUsZmlsbD1kYXRhc2V0X2JhdGNoKSxhbHBoYT0wLjcpKwogICAgICAgICAgICBzY2FsZV95X2NvbnRpbnVvdXMoZXhwYW5kID0gYygwLDApKSsKICAgICAgICAgICAgc2NhbGVfeF9jb250aW51b3VzKGV4cGFuZCA9IGMoMCwwKSkrCiAgICAgICAgICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0idG9wIikrdGhlbWVfdXNlCgpwX21vbm9jbGVfY2FyREVDX2Rlbm9pc2VkX2FsbD1lZ2c6OmdnYXJyYW5nZShwX2NhckRFQ19kZW5vaXNlZF9hbGxfMSxwX2NhckRFQ19kZW5vaXNlZF9hbGxfMixwX2NhckRFQ19kZW5vaXNlZF9hbGxfMyxuY29sPTMsZHJhdz1GKQpgYGAKCgpgYGB7ciwgZmlnLmhlaWdodD01LGZpZy53aWR0aD0xOH0KcF9tb25vY2xlX2NhckRFQ19kZW5vaXNlZF9hbGwKYGBgCgpgYGB7cn0KI2Nkc19leHBycz1GZXRjaERhdGEob2JqMCx2YXJzID0gYygiRkNHUjNBIiwiUzEwMEE4IikpCiNkZjA9ZGF0YS5mcmFtZShjYmluZChwc2V1ZG90aW1lPXBEYXRhKGNkcykkUHNldWRvdGltZSxjZHNfZXhwcnMpKQpjZHNfZXhwcnM9YXMubWF0cml4KFNpbmdsZUNlbGxFeHBlcmltZW50Ojpjb3VudHMoY2RzKVtjKCJGQ0dSM0EiLCJTMTAwQTgiKSxdKQpkZjA9ZGF0YS5mcmFtZShjYmluZChwc2V1ZG90aW1lPXBEYXRhKGNkcykkUHNldWRvdGltZSxsb2cxcCh0KGNkc19leHBycykqbXR4X3NpemVmYWN0b3IpKSkKZGYwJFVNQVBfMT1yZWR1Y2VkRGltcyhjZHMpJFVNQVBbLDFdCmRmMCRVTUFQXzI9cmVkdWNlZERpbXMoY2RzKSRVTUFQWywyXQpkZjAkQmF0Y2hJRD1wRGF0YShjZHMpJGRhdGFzZXRfYmF0Y2gKZGYwPWRmMFtpcy5maW5pdGUoZGYwJHBzZXVkb3RpbWUpLF0KZGYwPWRmMFtvcmRlcihkZjAkcHNldWRvdGltZSxkZWNyZWFzaW5nID0gRiksLGRyb3A9Rl0KZGYwJHg9ZGYwJHBzZXVkb3RpbWUvbWF4KGRmMCRwc2V1ZG90aW1lKQpkZl9wc2V1ZG90aW1lX2xpc3QkY2FyREVDX2Rlbm9pc2VkX2FsbD1kZjAKYGBgCgotIEZlYXR1cmUgcGxvdHMgb2YgYEZDR1IzQWAgYW5kIGBTMTAwQThgCgpgYGB7cn0KcD1nZXRfcGxvdDQoZGYwMCA9IGRmMCkKYGBgCgpgYGB7ciwgZmlnLmhlaWdodD00LGZpZy53aWR0aD0xOH0KcApgYGAKCmBgYHtyfQpkZl9kZW49Y29sRGF0YShjZHMpCnR0MT1rcy50ZXN0KGRmX2RlbiRQc2V1ZG90aW1lW2RmX2RlbiRkYXRhc2V0X2JhdGNoPT0iVDEiXSxkZl9kZW4kUHNldWRvdGltZVtkZl9kZW4kZGF0YXNldF9iYXRjaD09IlQzIl0pCnR0MQp0dDI9a3MudGVzdChkZl9kZW4kUHNldWRvdGltZVtkZl9kZW4kZGF0YXNldF9iYXRjaD09IlQxIl0sZGZfZGVuJFBzZXVkb3RpbWVbZGZfZGVuJGRhdGFzZXRfYmF0Y2g9PSJUMiJdKQp0dDIKdHQzPWtzLnRlc3QoZGZfZGVuJFBzZXVkb3RpbWVbZGZfZGVuJGRhdGFzZXRfYmF0Y2g9PSJUMiJdLGRmX2RlbiRQc2V1ZG90aW1lW2RmX2RlbiRkYXRhc2V0X2JhdGNoPT0iVDMiXSkKdHQzCmBgYAoKYGBge3J9ClN0YWJsZTVbNSwyOjRdPW1hdHJpeChnZXRfcF9uZXcoYyh0dDEkcC52YWx1ZSx0dDIkcC52YWx1ZSx0dDMkcC52YWx1ZSksYyh0dDEkc3RhdGlzdGljLHR0MiRzdGF0aXN0aWMsdHQzJHN0YXRpc3RpYykpLDEsMykKYGBgCgojIE1vbm9jbGUzIHVzaW5nIHNjVkkKCmBgYHtyfQojYWRhdGE9YWQkcmVhZF9oNWFkKCIuLi9maW5hbF9wcm9jZXNzZWRfcmVzdWx0cy9zY1ZJIFJlc3VsdHMvbW9ub2N5dGVzX0FMTC9hZGF0YV9hbGwuaDVhZCIpCmFkYXRhPWFkJHJlYWRfaDVhZCgiLi4vZmluYWxfcHJvY2Vzc2VkX3Jlc3VsdHMvc2NWSSBSZXN1bHRzIE5ldy9tb25vY3l0ZXNfQUxML2FkYXRhX2FsbC5oNWFkIikKYGBgCgpgYGB7cn0KY2VsbC5tZXRhLmRhdGE9cHlfdG9fcihhZGF0YSRvYnMpCmNlbGwubWV0YS5kYXRhJGRhdGFzZXRfYmF0Y2g9cGx5cjo6bWFwdmFsdWVzKGNlbGwubWV0YS5kYXRhJGJhdGNoX2xhYmVsLG5hbWVzKG1hcHJ1bGVzKSxtYXBydWxlcykKZ2VuZV9hbm4wPXB5X3RvX3IoYWRhdGEkdmFyKQpnZW5lX2Fubj1kYXRhLmZyYW1lKGdlbmVfc2hvcnRfbmFtZSA9IG1ha2UudW5pcXVlKHJvd25hbWVzKGdlbmVfYW5uMCkpLAogICAgICAgICAgICAgICAgICAgIHJvdy5uYW1lcyA9IG1ha2UudW5pcXVlKHJvd25hbWVzKGdlbmVfYW5uMCkpKQptdHg9dChweV90b19yKGFkYXRhJFgpKQpjb2xuYW1lcyhtdHgpPWNlbGwubWV0YS5kYXRhJGNlbGxuYW1lCnJvd25hbWVzKG10eCk9cm93bmFtZXMoZ2VuZV9hbm4pCm10eF9zaXplZmFjdG9yPTFlNC9jb2xTdW1zKG10eCkKYGBgCgojIyBVc2luZyBsYXRlbnQKCmBgYHtyfQojbXR4PW10eFtnZW5lX2FubiRWYXJpYW5jZVR5cGU9PSJIVkciLF0KY2RzIDwtIG5ld19jZWxsX2RhdGFfc2V0KG10eCwgY2VsbF9tZXRhZGF0YSA9IGNlbGwubWV0YS5kYXRhLGdlbmVfbWV0YWRhdGEgPWdlbmVfYW5uKQojIyBTdGVwIDE6IE5vcm1hbGl6ZSBhbmQgcHJlLXByb2Nlc3MgdGhlIGRhdGEKY2RzIDwtIHByZXByb2Nlc3NfY2RzKGNkcywgbnVtX2RpbSA9IDMyLG1ldGhvZD0iUENBIixub3JtX21ldGhvZD0ibG9nIix2ZXJib3NlID0gRikKdG1wMD1weV90b19yKGFkYXRhJG9ic21bIlhfbGF0ZW50Il0pCmNvbG5hbWVzKHRtcDApPXBhc3RlMCgiUEMiLDE6bmNvbCh0bXAwKSkKcmVkdWNlZERpbXMoY2RzKSRQQ0E9dG1wMAoKIyMgU3RlcCAyOiBSZW1vdmUgYmF0Y2ggZWZmZWN0cyB3aXRoIGNlbGwgYWxpZ25tZW50CiMjY2RzIDwtIGFsaWduX2NkcyhjZHMsIGFsaWdubWVudF9ncm91cCA9ICJCYXRjaElEIiwgcmVzaWR1YWxfbW9kZWxfZm9ybXVsYV9zdHIgPSBOVUxMKQojIyBTdGVwIDM6IFJlZHVjZSB0aGUgZGltZW5zaW9ucyB1c2luZyBVTUFQCmNkcyA8LSByZWR1Y2VfZGltZW5zaW9uKGNkcyxyZWR1Y3Rpb25fbWV0aG9kID0gIlVNQVAiLHByZXByb2Nlc3NfbWV0aG9kPSJQQ0EiLHZlcmJvc2UgPSBGKQoKIyMgU3RlcCA0OiBDbHVzdGVyIHRoZSBjZWxscwpjZHMgPC0gY2x1c3Rlcl9jZWxscyhjZHMscmVkdWN0aW9uX21ldGhvZCA9IlVNQVAiLGNsdXN0ZXJfbWV0aG9kID0gImxlaWRlbiIsdmVyYm9zZSA9IEYpCgojIENvbnN0cnVjdCB0aGUgZ3JhcGgKIyBOb3RlIHRoYXQsIGZvciB0aGUgcmVzdCBvZiB0aGUgY29kZSB0byBydW4sIHRoZSBncmFwaCBzaG91bGQgYmUgZnVsbHkgKHBhcnRpb25seSkgY29ubmVjdGVkCiMjIFN0ZXAgNTogTGVhcm4gYSBncmFwaApjZHMgPC0gbGVhcm5fZ3JhcGgoY2RzLCB1c2VfcGFydGl0aW9uID0gVCx2ZXJib3NlID0gRikKY29sRGF0YShjZHMpJGNsdXN0ZXJzPWNkc0BjbHVzdGVycyRVTUFQJGNsdXN0ZXJzCnAxPXBsb3RfY2VsbHMoY2RzLGNvbG9yX2NlbGxzX2J5ID0gInBhcnRpdGlvbiIsbGFiZWxfY2VsbF9ncm91cHMgPSBGKSt0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIikKcDI9cGxvdF9jZWxscyhjZHMsY29sb3JfY2VsbHNfYnkgPSAiY2x1c3RlcnMiLGxhYmVsX2NlbGxfZ3JvdXBzPUYsZ3JhcGhfbGFiZWxfc2l6ZT0yLCBsYWJlbF9sZWF2ZXM9RixsYWJlbF9icmFuY2hfcG9pbnRzPUYpK3RoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiKQpwPWNvd3Bsb3Q6OnBsb3RfZ3JpZChwMSxwMixhbGlnbiA9ICJoIixuY29sID0gMykKYGBgCgpgYGB7ciwgZmlnLmhlaWdodD01LGZpZy53aWR0aD0xOH0KcApgYGAKCmBgYHtyfQojIyBTdGVwIDY6IE9yZGVyIGNlbGxzCiMgcm9vdCBjZWxscwppZHM9Z2V0X2VhcmxpZXN0X3ByaW5jaXBhbF9ub2RlKGNkcyxjbHVzdGVyPWMoIjMiKSkKY2RzIDwtIG9yZGVyX2NlbGxzKGNkcywgcm9vdF9wcl9ub2Rlcz1pZHMpCiNwbG90X2NlbGxzKGNkcyxjb2xvcl9jZWxsc19ieSA9ICJwc2V1ZG90aW1lIikKYGBgCgoKYGBge3IsZmlnLmhlaWdodD01LGZpZy53aWR0aD0xOH0KY29sRGF0YShjZHMpJHBzZXVkb3RpbWU9cHNldWRvdGltZShjZHMpCmNvbERhdGEoY2RzKSRQc2V1ZG90aW1lPWNvbERhdGEoY2RzKSRwc2V1ZG90aW1lL21heChjb2xEYXRhKGNkcykkcHNldWRvdGltZSxuYS5ybSA9IFQpCiNzYXZlUkRTKGNkcyxmaWxlID0gImNkc19zY3ZpLnJkcyIpCmRmX2Rlbj1wRGF0YShjZHMpWyxjKCJQc2V1ZG90aW1lIiwiZGF0YXNldF9iYXRjaCIpXQpkZl9kZW49YXMuZGF0YS5mcmFtZShkZl9kZW5bIWlzLmluZmluaXRlKGRmX2RlbiRQc2V1ZG90aW1lKSxdKQpzZXQuc2VlZCgxMCkKCnRoZW1lX3VzZT10aGVtZShsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTE2KSwKICAgICAgICAgICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTIwKSkKCnBfc2NWSV9sYXRlbnRfYWxsXzE9cGxvdF9jZWxscyhjZHMsY29sb3JfY2VsbHNfYnkgPSAiZGF0YXNldF9iYXRjaCIsLGdyYXBoX2xhYmVsX3NpemU9MCxhbHBoYT0xLGNlbGxfc2l6ZSA9IDAuNikrCiAgZ3VpZGVzKGNvbG91ciA9IGd1aWRlX2xlZ2VuZChvdmVycmlkZS5hZXMgPSBsaXN0KGFscGhhPTAuNywgc2l6ZT01KSkpKwogIHRoZW1lX3VzZSsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIikKICAgICAgICAgIApwX3NjVklfbGF0ZW50X2FsbF8yPXBsb3RfY2VsbHMoY2RzLGNvbG9yX2NlbGxzX2J5ID0gIlBzZXVkb3RpbWUiLGxhYmVsX2JyYW5jaF9wb2ludHM9VCxncmFwaF9sYWJlbF9zaXplPTIsYWxwaGE9MSxjZWxsX3NpemUgPSAwLjYpKwogICAgICAgICAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIiwKICAgICAgICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQodmp1c3QgPSAwLjIpLAogICAgICAgICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KGFuZ2xlPS01MCApLAogICAgICAgICAgICAgICAgICBsZWdlbmQua2V5LmhlaWdodCA9IHVuaXQoMC41LCJjbSIpLAogICAgICAgICAgICAgICAgICBsZWdlbmQua2V5LndpZHRoID0gdW5pdCgxLCJjbSIpKSsKICAgICAgICAgICAgZ3VpZGVzKGNvbG9yID0gZ3VpZGVfY29sb3VyYmFyKGxhYmVsLnBvc2l0aW9uID0gInRvcCIpKSt0aGVtZV91c2UKCnBfc2NWSV9sYXRlbnRfYWxsXzM9Z2dwbG90KGRhdGE9ZGZfZGVuKStnZW9tX2RlbnNpdHkoYWVzKHg9UHNldWRvdGltZSxmaWxsPWRhdGFzZXRfYmF0Y2gpLGFscGhhPTAuNykrCiAgICAgICAgICAgIHNjYWxlX3lfY29udGludW91cyhleHBhbmQgPSBjKDAsMCkpKwogICAgICAgICAgICBzY2FsZV94X2NvbnRpbnVvdXMoZXhwYW5kID0gYygwLDApKSsKICAgICAgICAgICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJ0b3AiKSt0aGVtZV91c2UKCnBfbW9ub2NsZV9zY1ZJX2xhdGVudF9hbGw9ZWdnOjpnZ2FycmFuZ2UocF9zY1ZJX2xhdGVudF9hbGxfMSxwX3NjVklfbGF0ZW50X2FsbF8yLHBfc2NWSV9sYXRlbnRfYWxsXzMsbmNvbD0zLGRyYXc9RikKYGBgCgpgYGB7ciwgZmlnLmhlaWdodD01LGZpZy53aWR0aD0xOH0KcF9tb25vY2xlX3NjVklfbGF0ZW50X2FsbApgYGAKCgoKYGBge3J9CiNjZHNfZXhwcnM9RmV0Y2hEYXRhKG9iajAsdmFycyA9IGMoIkZDR1IzQSIsIlMxMDBBOCIpKQojZGYwPWRhdGEuZnJhbWUoY2JpbmQocHNldWRvdGltZT1wRGF0YShjZHMpJFBzZXVkb3RpbWUsY2RzX2V4cHJzKSkKY2RzX2V4cHJzPWFzLm1hdHJpeChTaW5nbGVDZWxsRXhwZXJpbWVudDo6Y291bnRzKGNkcylbYygiRkNHUjNBIiwiUzEwMEE4IiksXSkKI2RmMD1kYXRhLmZyYW1lKGNiaW5kKHBzZXVkb3RpbWU9cERhdGEoY2RzKSRQc2V1ZG90aW1lLGxvZzFwKHQoY2RzX2V4cHJzKSptdHhfc2l6ZWZhY3RvcikpKQpkZjA9ZGF0YS5mcmFtZShjYmluZChwc2V1ZG90aW1lPXBEYXRhKGNkcykkUHNldWRvdGltZSx0KGNkc19leHBycykpKQpkZjAkVU1BUF8xPXJlZHVjZWREaW1zKGNkcykkVU1BUFssMV0KZGYwJFVNQVBfMj1yZWR1Y2VkRGltcyhjZHMpJFVNQVBbLDJdCmRmMCRCYXRjaElEPXBEYXRhKGNkcykkZGF0YXNldF9iYXRjaApkZjA9ZGYwW2lzLmZpbml0ZShkZjAkcHNldWRvdGltZSksXQpkZjA9ZGYwW29yZGVyKGRmMCRwc2V1ZG90aW1lLGRlY3JlYXNpbmcgPSBGKSwsZHJvcD1GXQpkZjAkeD1kZjAkcHNldWRvdGltZS9tYXgoZGYwJHBzZXVkb3RpbWUpCmRmX3BzZXVkb3RpbWVfbGlzdCRzY1ZJX2xhdGVudF9hbGw9ZGYwCmBgYAoKLSBGZWF0dXJlIHBsb3RzIG9mIGBGQ0dSM0FgIGFuZCBgUzEwMEE4YAoKYGBge3J9CnA9Z2V0X3Bsb3Q0KGRmMDAgPSBkZjApCmBgYAoKYGBge3IsIGZpZy5oZWlnaHQ9NCxmaWcud2lkdGg9MTh9CnAKYGBgCgpgYGB7cn0KZGZfZGVuPWNvbERhdGEoY2RzKQp0dDE9a3MudGVzdChkZl9kZW4kUHNldWRvdGltZVtkZl9kZW4kZGF0YXNldF9iYXRjaD09IlQxIl0sZGZfZGVuJFBzZXVkb3RpbWVbZGZfZGVuJGRhdGFzZXRfYmF0Y2g9PSJUMyJdKQp0dDEKdHQyPWtzLnRlc3QoZGZfZGVuJFBzZXVkb3RpbWVbZGZfZGVuJGRhdGFzZXRfYmF0Y2g9PSJUMSJdLGRmX2RlbiRQc2V1ZG90aW1lW2RmX2RlbiRkYXRhc2V0X2JhdGNoPT0iVDIiXSkKdHQyCnR0Mz1rcy50ZXN0KGRmX2RlbiRQc2V1ZG90aW1lW2RmX2RlbiRkYXRhc2V0X2JhdGNoPT0iVDIiXSxkZl9kZW4kUHNldWRvdGltZVtkZl9kZW4kZGF0YXNldF9iYXRjaD09IlQzIl0pCnR0MwpgYGAKCmBgYHtyfQpTdGFibGU1WzYsMjo0XT1tYXRyaXgoZ2V0X3BfbmV3KGModHQxJHAudmFsdWUsdHQyJHAudmFsdWUsdHQzJHAudmFsdWUpLGModHQxJHN0YXRpc3RpYyx0dDIkc3RhdGlzdGljLHR0MyRzdGF0aXN0aWMpKSwxLDMpCmBgYAoKCiMjIEhWR3MgZGVub2lzZWQKCgpgYGB7cn0KY2RzIDwtIG5ld19jZWxsX2RhdGFfc2V0KG10eFtyb3duYW1lcyhtdHgpJWluJWh2Z19nZW5lcyRnZW5lbmFtZSxdLCBjZWxsX21ldGFkYXRhID0gY2VsbC5tZXRhLmRhdGEsZ2VuZV9tZXRhZGF0YSA9Z2VuZV9hbm5bZ2VuZV9hbm4kZ2VuZV9zaG9ydF9uYW1lJWluJWh2Z19nZW5lcyRnZW5lbmFtZSwsZHJvcD1GXSkKIyMgU3RlcCAxOiBOb3JtYWxpemUgYW5kIHByZS1wcm9jZXNzIHRoZSBkYXRhCmNkcyA8LSBwcmVwcm9jZXNzX2NkcyhjZHMsIG51bV9kaW0gPSAzMixtZXRob2Q9IlBDQSIsbm9ybV9tZXRob2Q9ImxvZyIsdmVyYm9zZSA9IEYpCgojIyBTdGVwIDI6IFJlbW92ZSBiYXRjaCBlZmZlY3RzIHdpdGggY2VsbCBhbGlnbm1lbnQKIyNjZHMgPC0gYWxpZ25fY2RzKGNkcywgYWxpZ25tZW50X2dyb3VwID0gIkJhdGNoSUQiLCByZXNpZHVhbF9tb2RlbF9mb3JtdWxhX3N0ciA9IE5VTEwpCiMjIFN0ZXAgMzogUmVkdWNlIHRoZSBkaW1lbnNpb25zIHVzaW5nIFVNQVAKY2RzIDwtIHJlZHVjZV9kaW1lbnNpb24oY2RzLHJlZHVjdGlvbl9tZXRob2QgPSAiVU1BUCIscHJlcHJvY2Vzc19tZXRob2Q9IlBDQSIsdmVyYm9zZSA9IEYpCgojIyBTdGVwIDQ6IENsdXN0ZXIgdGhlIGNlbGxzCmNkcyA8LSBjbHVzdGVyX2NlbGxzKGNkcyxyZWR1Y3Rpb25fbWV0aG9kID0iVU1BUCIsY2x1c3Rlcl9tZXRob2QgPSAibGVpZGVuIix2ZXJib3NlID0gRikKCiMgQ29uc3RydWN0IHRoZSBncmFwaAojIE5vdGUgdGhhdCwgZm9yIHRoZSByZXN0IG9mIHRoZSBjb2RlIHRvIHJ1biwgdGhlIGdyYXBoIHNob3VsZCBiZSBmdWxseSAocGFydGlvbmx5KSBjb25uZWN0ZWQKIyMgU3RlcCA1OiBMZWFybiBhIGdyYXBoCmNkcyA8LSBsZWFybl9ncmFwaChjZHMsIHVzZV9wYXJ0aXRpb24gPSBULHZlcmJvc2UgPSBGKQpjb2xEYXRhKGNkcykkY2x1c3RlcnM9Y2RzQGNsdXN0ZXJzJFVNQVAkY2x1c3RlcnMKcDE9cGxvdF9jZWxscyhjZHMsY29sb3JfY2VsbHNfYnkgPSAicGFydGl0aW9uIixsYWJlbF9jZWxsX2dyb3VwcyA9IEYpK3RoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiKQpwMj1wbG90X2NlbGxzKGNkcyxjb2xvcl9jZWxsc19ieSA9ICJjbHVzdGVycyIsbGFiZWxfY2VsbF9ncm91cHM9RixncmFwaF9sYWJlbF9zaXplPTIsIGxhYmVsX2xlYXZlcz1GLGxhYmVsX2JyYW5jaF9wb2ludHM9RikrdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIpCnA9Y293cGxvdDo6cGxvdF9ncmlkKHAxLHAyLGFsaWduID0gImgiLG5jb2wgPSAzKQpgYGAKCmBgYHtyLCBmaWcuaGVpZ2h0PTUsZmlnLndpZHRoPTE4fQpwCmBgYAoKYGBge3J9CiMjIFN0ZXAgNjogT3JkZXIgY2VsbHMKIyByb290IGNlbGxzCmlkcz1nZXRfZWFybGllc3RfcHJpbmNpcGFsX25vZGUoY2RzLGNsdXN0ZXI9YygiMyIpKQpjZHMgPC0gb3JkZXJfY2VsbHMoY2RzLCByb290X3ByX25vZGVzPWlkcykKI3Bsb3RfY2VsbHMoY2RzLGNvbG9yX2NlbGxzX2J5ID0gInBzZXVkb3RpbWUiKQpgYGAKCgpgYGB7cixmaWcuaGVpZ2h0PTUsZmlnLndpZHRoPTE4fQpjb2xEYXRhKGNkcykkcHNldWRvdGltZT1wc2V1ZG90aW1lKGNkcykKY29sRGF0YShjZHMpJFBzZXVkb3RpbWU9Y29sRGF0YShjZHMpJHBzZXVkb3RpbWUvbWF4KGNvbERhdGEoY2RzKSRwc2V1ZG90aW1lLG5hLnJtID0gVCkKZGZfZGVuPXBEYXRhKGNkcylbLGMoIlBzZXVkb3RpbWUiLCJkYXRhc2V0X2JhdGNoIildCmRmX2Rlbj1hcy5kYXRhLmZyYW1lKGRmX2RlblshaXMuaW5maW5pdGUoZGZfZGVuJFBzZXVkb3RpbWUpLF0pCnNldC5zZWVkKDEwKQoKdGhlbWVfdXNlPXRoZW1lKGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9MTYpLAogICAgICAgICAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9MjApKQoKcF9zY3ZpX2Rlbm9pc2VkX2h2Z18xPXBsb3RfY2VsbHMoY2RzLGNvbG9yX2NlbGxzX2J5ID0gImRhdGFzZXRfYmF0Y2giLCxncmFwaF9sYWJlbF9zaXplPTAsYWxwaGE9MSxjZWxsX3NpemUgPSAwLjYpKwogIGd1aWRlcyhjb2xvdXIgPSBndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID0gbGlzdChhbHBoYT0wLjcsIHNpemU9NSkpKSsKICB0aGVtZV91c2UrCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIpCiAgICAgICAgICAKcF9zY3ZpX2Rlbm9pc2VkX2h2Z18yPXBsb3RfY2VsbHMoY2RzLGNvbG9yX2NlbGxzX2J5ID0gIlBzZXVkb3RpbWUiLGxhYmVsX2JyYW5jaF9wb2ludHM9VCxncmFwaF9sYWJlbF9zaXplPTIsYWxwaGE9MSxjZWxsX3NpemUgPSAwLjYpKwogICAgICAgICAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIiwKICAgICAgICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQodmp1c3QgPSAwLjIpLAogICAgICAgICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KGFuZ2xlPS01MCApLAogICAgICAgICAgICAgICAgICBsZWdlbmQua2V5LmhlaWdodCA9IHVuaXQoMC41LCJjbSIpLAogICAgICAgICAgICAgICAgICBsZWdlbmQua2V5LndpZHRoID0gdW5pdCgxLCJjbSIpKSsKICAgICAgICAgICAgZ3VpZGVzKGNvbG9yID0gZ3VpZGVfY29sb3VyYmFyKGxhYmVsLnBvc2l0aW9uID0gInRvcCIpKSt0aGVtZV91c2UKCnBfc2N2aV9kZW5vaXNlZF9odmdfMz1nZ3Bsb3QoZGF0YT1kZl9kZW4pK2dlb21fZGVuc2l0eShhZXMoeD1Qc2V1ZG90aW1lLGZpbGw9ZGF0YXNldF9iYXRjaCksYWxwaGE9MC43KSsKICAgICAgICAgICAgc2NhbGVfeV9jb250aW51b3VzKGV4cGFuZCA9IGMoMCwwKSkrCiAgICAgICAgICAgIHNjYWxlX3hfY29udGludW91cyhleHBhbmQgPSBjKDAsMCkpKwogICAgICAgICAgICB0aGVtZShsZWdlbmQucG9zaXRpb249InRvcCIpK3RoZW1lX3VzZQoKcF9tb25vY2xlX3NjdmlfZGVub2lzZWRfaHZnPWVnZzo6Z2dhcnJhbmdlKHBfc2N2aV9kZW5vaXNlZF9odmdfMSxwX3NjdmlfZGVub2lzZWRfaHZnXzIscF9zY3ZpX2Rlbm9pc2VkX2h2Z18zLG5jb2w9MyxkcmF3PUYpCmBgYAoKYGBge3IsIGZpZy5oZWlnaHQ9NSxmaWcud2lkdGg9MTh9CnBfbW9ub2NsZV9zY3ZpX2Rlbm9pc2VkX2h2ZwpgYGAKCmBgYHtyfQojY2RzX2V4cHJzPUZldGNoRGF0YShvYmowLHZhcnMgPSBjKCJGQ0dSM0EiLCJTMTAwQTgiKSkKI2RmMD1kYXRhLmZyYW1lKGNiaW5kKHBzZXVkb3RpbWU9cERhdGEoY2RzKSRQc2V1ZG90aW1lLGNkc19leHBycykpCmNkc19leHBycz1hcy5tYXRyaXgoU2luZ2xlQ2VsbEV4cGVyaW1lbnQ6OmNvdW50cyhjZHMpW2MoIkZDR1IzQSIsIlMxMDBBOCIpLF0pCiNkZjA9ZGF0YS5mcmFtZShjYmluZChwc2V1ZG90aW1lPXBEYXRhKGNkcykkUHNldWRvdGltZSxsb2cxcCh0KGNkc19leHBycykqbXR4X3NpemVmYWN0b3IpKSkKZGYwPWRhdGEuZnJhbWUoY2JpbmQocHNldWRvdGltZT1wRGF0YShjZHMpJFBzZXVkb3RpbWUsdChjZHNfZXhwcnMpKSkKZGYwJFVNQVBfMT1yZWR1Y2VkRGltcyhjZHMpJFVNQVBbLDFdCmRmMCRVTUFQXzI9cmVkdWNlZERpbXMoY2RzKSRVTUFQWywyXQpkZjAkQmF0Y2hJRD1wRGF0YShjZHMpJGRhdGFzZXRfYmF0Y2gKZGYwPWRmMFtpcy5maW5pdGUoZGYwJHBzZXVkb3RpbWUpLF0KZGYwPWRmMFtvcmRlcihkZjAkcHNldWRvdGltZSxkZWNyZWFzaW5nID0gRiksLGRyb3A9Rl0KZGYwJHg9ZGYwJHBzZXVkb3RpbWUvbWF4KGRmMCRwc2V1ZG90aW1lKQpkZl9wc2V1ZG90aW1lX2xpc3Qkc2NWSV9kZW5vc2llZF9odmc9ZGYwCmBgYAoKLSBGZWF0dXJlIHBsb3RzIG9mIGBGQ0dSM0FgIGFuZCBgUzEwMEE4YAoKYGBge3J9CnA9Z2V0X3Bsb3Q0KGRmMDAgPSBkZjApCmBgYAoKYGBge3IsIGZpZy5oZWlnaHQ9NCxmaWcud2lkdGg9MTh9CnAKYGBgCgpgYGB7cn0KZGZfZGVuPWNvbERhdGEoY2RzKQp0dDE9a3MudGVzdChkZl9kZW4kUHNldWRvdGltZVtkZl9kZW4kZGF0YXNldF9iYXRjaD09IlQxIl0sZGZfZGVuJFBzZXVkb3RpbWVbZGZfZGVuJGRhdGFzZXRfYmF0Y2g9PSJUMyJdKQp0dDEKdHQyPWtzLnRlc3QoZGZfZGVuJFBzZXVkb3RpbWVbZGZfZGVuJGRhdGFzZXRfYmF0Y2g9PSJUMSJdLGRmX2RlbiRQc2V1ZG90aW1lW2RmX2RlbiRkYXRhc2V0X2JhdGNoPT0iVDIiXSkKdHQyCnR0Mz1rcy50ZXN0KGRmX2RlbiRQc2V1ZG90aW1lW2RmX2RlbiRkYXRhc2V0X2JhdGNoPT0iVDIiXSxkZl9kZW4kUHNldWRvdGltZVtkZl9kZW4kZGF0YXNldF9iYXRjaD09IlQzIl0pCnR0MwpgYGAKCmBgYHtyfQpTdGFibGU1WzcsMjo0XT1tYXRyaXgoZ2V0X3BfbmV3KGModHQxJHAudmFsdWUsdHQyJHAudmFsdWUsdHQzJHAudmFsdWUpLGModHQxJHN0YXRpc3RpYyx0dDIkc3RhdGlzdGljLHR0MyRzdGF0aXN0aWMpKSwxLDMpCmBgYAoKIyMgQWxsIGdlbmVzIGRlbm9pc2VkCgpgYGB7cn0KY2RzIDwtIG5ld19jZWxsX2RhdGFfc2V0KG10eCwgY2VsbF9tZXRhZGF0YSA9IGNlbGwubWV0YS5kYXRhLGdlbmVfbWV0YWRhdGEgPWdlbmVfYW5uKQojIyBTdGVwIDE6IE5vcm1hbGl6ZSBhbmQgcHJlLXByb2Nlc3MgdGhlIGRhdGEKY2RzIDwtIHByZXByb2Nlc3NfY2RzKGNkcywgbnVtX2RpbSA9IDMyLG1ldGhvZD0iUENBIixub3JtX21ldGhvZD0ibG9nIix2ZXJib3NlID0gRikKCiMjIFN0ZXAgMjogUmVtb3ZlIGJhdGNoIGVmZmVjdHMgd2l0aCBjZWxsIGFsaWdubWVudAojI2NkcyA8LSBhbGlnbl9jZHMoY2RzLCBhbGlnbm1lbnRfZ3JvdXAgPSAiQmF0Y2hJRCIsIHJlc2lkdWFsX21vZGVsX2Zvcm11bGFfc3RyID0gTlVMTCkKIyMgU3RlcCAzOiBSZWR1Y2UgdGhlIGRpbWVuc2lvbnMgdXNpbmcgVU1BUApjZHMgPC0gcmVkdWNlX2RpbWVuc2lvbihjZHMscmVkdWN0aW9uX21ldGhvZCA9ICJVTUFQIixwcmVwcm9jZXNzX21ldGhvZD0iUENBIix2ZXJib3NlID0gRikKCiMjIFN0ZXAgNDogQ2x1c3RlciB0aGUgY2VsbHMKY2RzIDwtIGNsdXN0ZXJfY2VsbHMoY2RzLHJlZHVjdGlvbl9tZXRob2QgPSJVTUFQIixjbHVzdGVyX21ldGhvZCA9ICJsZWlkZW4iLHZlcmJvc2UgPSBGKQoKIyBDb25zdHJ1Y3QgdGhlIGdyYXBoCiMgTm90ZSB0aGF0LCBmb3IgdGhlIHJlc3Qgb2YgdGhlIGNvZGUgdG8gcnVuLCB0aGUgZ3JhcGggc2hvdWxkIGJlIGZ1bGx5IChwYXJ0aW9ubHkpIGNvbm5lY3RlZAojIyBTdGVwIDU6IExlYXJuIGEgZ3JhcGgKY2RzIDwtIGxlYXJuX2dyYXBoKGNkcywgdXNlX3BhcnRpdGlvbiA9IFQsdmVyYm9zZSA9IEYpCmNvbERhdGEoY2RzKSRjbHVzdGVycz1jZHNAY2x1c3RlcnMkVU1BUCRjbHVzdGVycwpwMT1wbG90X2NlbGxzKGNkcyxjb2xvcl9jZWxsc19ieSA9ICJwYXJ0aXRpb24iLGxhYmVsX2NlbGxfZ3JvdXBzID0gRikrdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIpCnAyPXBsb3RfY2VsbHMoY2RzLGNvbG9yX2NlbGxzX2J5ID0gImNsdXN0ZXJzIixsYWJlbF9jZWxsX2dyb3Vwcz1GLGdyYXBoX2xhYmVsX3NpemU9MiwgbGFiZWxfbGVhdmVzPUYsbGFiZWxfYnJhbmNoX3BvaW50cz1GKSt0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIikKcD1jb3dwbG90OjpwbG90X2dyaWQocDEscDIsYWxpZ24gPSAiaCIsbmNvbCA9IDMpCmBgYAoKYGBge3IsIGZpZy5oZWlnaHQ9NSxmaWcud2lkdGg9MTh9CnAKYGBgCgpgYGB7cn0KIyMgU3RlcCA2OiBPcmRlciBjZWxscwojIHJvb3QgY2VsbHMKaWRzPWdldF9lYXJsaWVzdF9wcmluY2lwYWxfbm9kZShjZHMsY2x1c3Rlcj1jKCIzIikpCmNkcyA8LSBvcmRlcl9jZWxscyhjZHMsIHJvb3RfcHJfbm9kZXM9aWRzKQojcGxvdF9jZWxscyhjZHMsY29sb3JfY2VsbHNfYnkgPSAicHNldWRvdGltZSIpCmBgYAoKCmBgYHtyLGZpZy5oZWlnaHQ9NSxmaWcud2lkdGg9MTh9CngwPXBzZXVkb3RpbWUoY2RzKQp4MFtpcy5pbmZpbml0ZSh4MCldPU5BCmNvbERhdGEoY2RzKSRwc2V1ZG90aW1lPXgwCgpjb2xEYXRhKGNkcykkUHNldWRvdGltZT1jb2xEYXRhKGNkcykkcHNldWRvdGltZS9tYXgoY29sRGF0YShjZHMpJHBzZXVkb3RpbWUsbmEucm0gPSBUKQpkZl9kZW49cERhdGEoY2RzKVssYygiUHNldWRvdGltZSIsImRhdGFzZXRfYmF0Y2giKV0KZGZfZGVuPWFzLmRhdGEuZnJhbWUoZGZfZGVuWyFpcy5pbmZpbml0ZShkZl9kZW4kUHNldWRvdGltZSksXSkKc2V0LnNlZWQoMTApCgp0aGVtZV91c2U9dGhlbWUobGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT0xNiksCiAgICAgICAgICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT0yMCkpCgpwX3NjVklfZGVub2lzZWRfYWxsXzE9cGxvdF9jZWxscyhjZHMsY29sb3JfY2VsbHNfYnkgPSAiZGF0YXNldF9iYXRjaCIsLGdyYXBoX2xhYmVsX3NpemU9MCxhbHBoYT0xLGNlbGxfc2l6ZSA9IDAuNikrCiAgZ3VpZGVzKGNvbG91ciA9IGd1aWRlX2xlZ2VuZChvdmVycmlkZS5hZXMgPSBsaXN0KGFscGhhPTAuNywgc2l6ZT01KSkpKwogIHRoZW1lX3VzZSsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIikKICAgICAgICAgIApwX3NjVklfZGVub2lzZWRfYWxsXzI9cGxvdF9jZWxscyhjZHMsY29sb3JfY2VsbHNfYnkgPSAiUHNldWRvdGltZSIsbGFiZWxfYnJhbmNoX3BvaW50cz1ULGdyYXBoX2xhYmVsX3NpemU9MixhbHBoYT0xLGNlbGxfc2l6ZSA9IDAuNikrCiAgICAgICAgICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiLAogICAgICAgICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dCh2anVzdCA9IDAuMiksCiAgICAgICAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoYW5nbGU9LTUwICksCiAgICAgICAgICAgICAgICAgIGxlZ2VuZC5rZXkuaGVpZ2h0ID0gdW5pdCgwLjUsImNtIiksCiAgICAgICAgICAgICAgICAgIGxlZ2VuZC5rZXkud2lkdGggPSB1bml0KDEsImNtIikpKwogICAgICAgICAgICBndWlkZXMoY29sb3IgPSBndWlkZV9jb2xvdXJiYXIobGFiZWwucG9zaXRpb24gPSAidG9wIikpK3RoZW1lX3VzZQoKcF9zY1ZJX2Rlbm9pc2VkX2FsbF8zPWdncGxvdChkYXRhPWRmX2RlbikrZ2VvbV9kZW5zaXR5KGFlcyh4PVBzZXVkb3RpbWUsZmlsbD1kYXRhc2V0X2JhdGNoKSxhbHBoYT0wLjcpKwogICAgICAgICAgICBzY2FsZV95X2NvbnRpbnVvdXMoZXhwYW5kID0gYygwLDApKSsKICAgICAgICAgICAgc2NhbGVfeF9jb250aW51b3VzKGV4cGFuZCA9IGMoMCwwKSkrCiAgICAgICAgICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0idG9wIikrdGhlbWVfdXNlCgpwX21vbm9jbGVfc2NWSV9kZW5vaXNlZF9hbGw9ZWdnOjpnZ2FycmFuZ2UocF9zY1ZJX2Rlbm9pc2VkX2FsbF8xLHBfc2NWSV9kZW5vaXNlZF9hbGxfMixwX3NjVklfZGVub2lzZWRfYWxsXzMsbmNvbD0zLGRyYXc9RikKYGBgCgpgYGB7ciBmaWcuaGVpZ2h0PTUsZmlnLndpZHRoPTE4fQpwX21vbm9jbGVfc2NWSV9kZW5vaXNlZF9hbGwKYGBgCgoKYGBge3J9CiNjZHNfZXhwcnM9RmV0Y2hEYXRhKG9iajAsdmFycyA9IGMoIkZDR1IzQSIsIlMxMDBBOCIpKQojZGYwPWRhdGEuZnJhbWUoY2JpbmQocHNldWRvdGltZT1wRGF0YShjZHMpJFBzZXVkb3RpbWUsY2RzX2V4cHJzKSkKY2RzX2V4cHJzPWFzLm1hdHJpeChTaW5nbGVDZWxsRXhwZXJpbWVudDo6Y291bnRzKGNkcylbYygiRkNHUjNBIiwiUzEwMEE4IiksXSkKI2RmMD1kYXRhLmZyYW1lKGNiaW5kKHBzZXVkb3RpbWU9cERhdGEoY2RzKSRQc2V1ZG90aW1lLGxvZzFwKHQoY2RzX2V4cHJzKSptdHhfc2l6ZWZhY3RvcikpKQpkZjA9ZGF0YS5mcmFtZShjYmluZChwc2V1ZG90aW1lPXBEYXRhKGNkcykkUHNldWRvdGltZSx0KGNkc19leHBycykpKQpkZjAkVU1BUF8xPXJlZHVjZWREaW1zKGNkcykkVU1BUFssMV0KZGYwJFVNQVBfMj1yZWR1Y2VkRGltcyhjZHMpJFVNQVBbLDJdCmRmMCRCYXRjaElEPXBEYXRhKGNkcykkZGF0YXNldF9iYXRjaApkZjA9ZGYwW2lzLmZpbml0ZShkZjAkcHNldWRvdGltZSksXQpkZjA9ZGYwW29yZGVyKGRmMCRwc2V1ZG90aW1lLGRlY3JlYXNpbmcgPSBGKSwsZHJvcD1GXQpkZjAkeD1kZjAkcHNldWRvdGltZS9tYXgoZGYwJHBzZXVkb3RpbWUpCmRmX3BzZXVkb3RpbWVfbGlzdCRzY1ZJX2Rlbm9zaWVkX2FsbD1kZjAKYGBgCgotIEZlYXR1cmUgcGxvdHMgb2YgYEZDR1IzQWAgYW5kIGBTMTAwQThgCgpgYGB7cn0KcD1nZXRfcGxvdDQoZGYwMCA9IGRmMCkKYGBgCgpgYGB7ciwgZmlnLmhlaWdodD00LGZpZy53aWR0aD0xOH0KcApgYGAKCmBgYHtyfQpkZl9kZW49Y29sRGF0YShjZHMpCnR0MT1rcy50ZXN0KGRmX2RlbiRQc2V1ZG90aW1lW2RmX2RlbiRkYXRhc2V0X2JhdGNoPT0iVDEiXSxkZl9kZW4kUHNldWRvdGltZVtkZl9kZW4kZGF0YXNldF9iYXRjaD09IlQzIl0pCnR0MQp0dDI9a3MudGVzdChkZl9kZW4kUHNldWRvdGltZVtkZl9kZW4kZGF0YXNldF9iYXRjaD09IlQxIl0sZGZfZGVuJFBzZXVkb3RpbWVbZGZfZGVuJGRhdGFzZXRfYmF0Y2g9PSJUMiJdKQp0dDIKdHQzPWtzLnRlc3QoZGZfZGVuJFBzZXVkb3RpbWVbZGZfZGVuJGRhdGFzZXRfYmF0Y2g9PSJUMiJdLGRmX2RlbiRQc2V1ZG90aW1lW2RmX2RlbiRkYXRhc2V0X2JhdGNoPT0iVDMiXSkKdHQzCmBgYAoKYGBge3J9ClN0YWJsZTVbOCwyOjRdPW1hdHJpeChnZXRfcF9uZXcoYyh0dDEkcC52YWx1ZSx0dDIkcC52YWx1ZSx0dDMkcC52YWx1ZSksYyh0dDEkc3RhdGlzdGljLHR0MiRzdGF0aXN0aWMsdHQzJHN0YXRpc3RpYykpLDEsMykKYGBgCgojIE1vbm9jbGUzIHVzaW5nIGRjYStjb21iYXQKCmBgYHtyfQojYWRhdGE9YWQkcmVhZF9oNWFkKCIuLi9maW5hbF9wcm9jZXNzZWRfcmVzdWx0cy9kY2EgUmVzdWx0cy9hZGF0YV9hbGwuaDVhZCIpCmFkYXRhPWFkJHJlYWRfaDVhZCgiLi4vZmluYWxfcHJvY2Vzc2VkX3Jlc3VsdHMvZGNhIFJlc3VsdHMgTmV3L2FkYXRhX2FsbC5oNWFkIikKYGBgCgpgYGB7cn0KY2VsbC5tZXRhLmRhdGE9cHlfdG9fcihhZGF0YSRvYnMpCmNlbGwubWV0YS5kYXRhJGRhdGFzZXRfYmF0Y2g9cGx5cjo6bWFwdmFsdWVzKGNlbGwubWV0YS5kYXRhJGJhdGNoX2xhYmVsLG5hbWVzKG1hcHJ1bGVzKSxtYXBydWxlcykKZ2VuZV9hbm4wPXB5X3RvX3IoYWRhdGEkdmFyKQpnZW5lX2Fubj1kYXRhLmZyYW1lKGdlbmVfc2hvcnRfbmFtZSA9IG1ha2UudW5pcXVlKHJvd25hbWVzKGdlbmVfYW5uMCkpLAogICAgICAgICAgICAgICAgICAgIHJvdy5uYW1lcyA9IG1ha2UudW5pcXVlKHJvd25hbWVzKGdlbmVfYW5uMCkpKQptdHg9dChweV90b19yKGFkYXRhJFgpKQpjb2xuYW1lcyhtdHgpPWNlbGwubWV0YS5kYXRhJGNlbGxuYW1lCnJvd25hbWVzKG10eCk9cm93bmFtZXMoZ2VuZV9hbm4pCm10eF9zaXplZmFjdG9yPTFlNC9jb2xTdW1zKG10eCkKYGBgCgojIyBVc2luZyBjb21iYXRlZCBsYXRlbnQgZnJvbSBkY2EKCmBgYHtyfQojbXR4PW10eFtnZW5lX2FubiRWYXJpYW5jZVR5cGU9PSJIVkciLF0KY2RzIDwtIG5ld19jZWxsX2RhdGFfc2V0KG10eCwgY2VsbF9tZXRhZGF0YSA9IGNlbGwubWV0YS5kYXRhLGdlbmVfbWV0YWRhdGEgPWdlbmVfYW5uKQojIyBTdGVwIDE6IE5vcm1hbGl6ZSBhbmQgcHJlLXByb2Nlc3MgdGhlIGRhdGEKY2RzIDwtIHByZXByb2Nlc3NfY2RzKGNkcywgbnVtX2RpbSA9IDMyLG1ldGhvZD0iUENBIixub3JtX21ldGhvZD0ibG9nIikKCnRtcDA9cHlfdG9fcihhZGF0YSRvYnNtWyJYX2RjYV9sYXRlbnQiXSkgI29yaWdpbmFsIGRjYQpjb2xuYW1lcyh0bXAwKT1wYXN0ZTAoIlBDIiwxOm5jb2wodG1wMCkpCnJlZHVjZWREaW1zKGNkcykkUENBPXRtcDAKCiMjIFN0ZXAgMjogUmVtb3ZlIGJhdGNoIGVmZmVjdHMgd2l0aCBjZWxsIGFsaWdubWVudAojI2NkcyA8LSBhbGlnbl9jZHMoY2RzLCBhbGlnbm1lbnRfZ3JvdXAgPSAiQmF0Y2hJRCIsIHJlc2lkdWFsX21vZGVsX2Zvcm11bGFfc3RyID0gTlVMTCkKIyMgU3RlcCAzOiBSZWR1Y2UgdGhlIGRpbWVuc2lvbnMgdXNpbmcgVU1BUApjZHMgPC0gcmVkdWNlX2RpbWVuc2lvbihjZHMscmVkdWN0aW9uX21ldGhvZCA9ICJVTUFQIixwcmVwcm9jZXNzX21ldGhvZD0iUENBIikKCiMjIFN0ZXAgNDogQ2x1c3RlciB0aGUgY2VsbHMKY2RzIDwtIGNsdXN0ZXJfY2VsbHMoY2RzLHJlZHVjdGlvbl9tZXRob2QgPSJVTUFQIixjbHVzdGVyX21ldGhvZCA9ICJsZWlkZW4iKQoKIyBDb25zdHJ1Y3QgdGhlIGdyYXBoCiMgTm90ZSB0aGF0LCBmb3IgdGhlIHJlc3Qgb2YgdGhlIGNvZGUgdG8gcnVuLCB0aGUgZ3JhcGggc2hvdWxkIGJlIGZ1bGx5IChwYXJ0aW9ubHkpIGNvbm5lY3RlZAojIyBTdGVwIDU6IExlYXJuIGEgZ3JhcGgKY2RzIDwtIGxlYXJuX2dyYXBoKGNkcywgdXNlX3BhcnRpdGlvbiA9IFQsdmVyYm9zZSA9IEYpCmNvbERhdGEoY2RzKSRjbHVzdGVycz1jZHNAY2x1c3RlcnMkVU1BUCRjbHVzdGVycwpwMT1wbG90X2NlbGxzKGNkcyxjb2xvcl9jZWxsc19ieSA9ICJwYXJ0aXRpb24iLGxhYmVsX2NlbGxfZ3JvdXBzID0gRikrdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIpCnAyPXBsb3RfY2VsbHMoY2RzLGNvbG9yX2NlbGxzX2J5ID0gImNsdXN0ZXJzIixsYWJlbF9jZWxsX2dyb3Vwcz1GLGdyYXBoX2xhYmVsX3NpemU9MiwgbGFiZWxfbGVhdmVzPUYsbGFiZWxfYnJhbmNoX3BvaW50cz1GKSt0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIikKcD1jb3dwbG90OjpwbG90X2dyaWQocDEscDIsYWxpZ24gPSAiaCIsbmNvbCA9IDMpCmBgYAoKYGBge3IgZmlnLmhlaWdodD01LGZpZy53aWR0aD0xOH0KcApgYGAKCmBgYHtyfQojIyBTdGVwIDY6IE9yZGVyIGNlbGxzCiMgcm9vdCBjZWxscwppZHM9Z2V0X2VhcmxpZXN0X3ByaW5jaXBhbF9ub2RlKGNkcyxjbHVzdGVyPWMoIjQiKSkKY2RzIDwtIG9yZGVyX2NlbGxzKGNkcywgcm9vdF9wcl9ub2Rlcz1pZHMpCiNwbG90X2NlbGxzKGNkcyxjb2xvcl9jZWxsc19ieSA9ICJwc2V1ZG90aW1lIikKYGBgCgoKYGBge3IsZmlnLmhlaWdodD01LGZpZy53aWR0aD0xOH0KY29sRGF0YShjZHMpJHBzZXVkb3RpbWU9cHNldWRvdGltZShjZHMpCmNvbERhdGEoY2RzKSRQc2V1ZG90aW1lPWNvbERhdGEoY2RzKSRwc2V1ZG90aW1lL21heChjb2xEYXRhKGNkcykkcHNldWRvdGltZSxuYS5ybSA9IFQpCiNzYXZlUkRTKGNkcyxmaWxlPSJjZHNfZGNhLnJkcyIpCmRmX2Rlbj1wRGF0YShjZHMpWyxjKCJQc2V1ZG90aW1lIiwiZGF0YXNldF9iYXRjaCIpXQpkZl9kZW49YXMuZGF0YS5mcmFtZShkZl9kZW5bIWlzLmluZmluaXRlKGRmX2RlbiRQc2V1ZG90aW1lKSxdKQpzZXQuc2VlZCgxMCkKCnRoZW1lX3VzZT10aGVtZShsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTE2KSwKICAgICAgICAgICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTIwKSkKCnBfZGNhX2xhdGVudF9hbGxfMT1wbG90X2NlbGxzKGNkcyxjb2xvcl9jZWxsc19ieSA9ICJkYXRhc2V0X2JhdGNoIiwsZ3JhcGhfbGFiZWxfc2l6ZT0wLGFscGhhPTEsY2VsbF9zaXplID0gMC42KSsKICBndWlkZXMoY29sb3VyID0gZ3VpZGVfbGVnZW5kKG92ZXJyaWRlLmFlcyA9IGxpc3QoYWxwaGE9MC43LCBzaXplPTUpKSkrCiAgdGhlbWVfdXNlKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiKQogICAgICAgICAgCnBfZGNhX2xhdGVudF9hbGxfMj1wbG90X2NlbGxzKGNkcyxjb2xvcl9jZWxsc19ieSA9ICJQc2V1ZG90aW1lIixsYWJlbF9icmFuY2hfcG9pbnRzPVQsZ3JhcGhfbGFiZWxfc2l6ZT0yLGFscGhhPTEsY2VsbF9zaXplID0gMC42KSsKICAgICAgICAgICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIsCiAgICAgICAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHZqdXN0ID0gMC4yKSwKICAgICAgICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChhbmdsZT0tNTAgKSwKICAgICAgICAgICAgICAgICAgbGVnZW5kLmtleS5oZWlnaHQgPSB1bml0KDAuNSwiY20iKSwKICAgICAgICAgICAgICAgICAgbGVnZW5kLmtleS53aWR0aCA9IHVuaXQoMSwiY20iKSkrCiAgICAgICAgICAgIGd1aWRlcyhjb2xvciA9IGd1aWRlX2NvbG91cmJhcihsYWJlbC5wb3NpdGlvbiA9ICJ0b3AiKSkrdGhlbWVfdXNlCgpwX2RjYV9sYXRlbnRfYWxsXzM9Z2dwbG90KGRhdGE9ZGZfZGVuKStnZW9tX2RlbnNpdHkoYWVzKHg9UHNldWRvdGltZSxmaWxsPWRhdGFzZXRfYmF0Y2gpLGFscGhhPTAuNykrCiAgICAgICAgICAgIHNjYWxlX3lfY29udGludW91cyhleHBhbmQgPSBjKDAsMCkpKwogICAgICAgICAgICBzY2FsZV94X2NvbnRpbnVvdXMoZXhwYW5kID0gYygwLDApKSsKICAgICAgICAgICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJ0b3AiKSt0aGVtZV91c2UKCnBfbW9ub2NsZV9kY2FfbGF0ZW50X2FsbD1lZ2c6OmdnYXJyYW5nZShwX2RjYV9sYXRlbnRfYWxsXzEscF9kY2FfbGF0ZW50X2FsbF8yLHBfZGNhX2xhdGVudF9hbGxfMyxuY29sPTMsZHJhdz1GKQpgYGAKCmBgYHtyIGZpZy5oZWlnaHQ9NSxmaWcud2lkdGg9MTh9CnBfbW9ub2NsZV9kY2FfbGF0ZW50X2FsbApgYGAKCmBgYHtyfQojY2RzX2V4cHJzPUZldGNoRGF0YShvYmowLHZhcnMgPSBjKCJGQ0dSM0EiLCJTMTAwQTgiKSkKI2RmMD1kYXRhLmZyYW1lKGNiaW5kKHBzZXVkb3RpbWU9cERhdGEoY2RzKSRQc2V1ZG90aW1lLGNkc19leHBycykpCmNkc19leHBycz1hcy5tYXRyaXgoU2luZ2xlQ2VsbEV4cGVyaW1lbnQ6OmNvdW50cyhjZHMpW2MoIkZDR1IzQSIsIlMxMDBBOCIpLF0pCiNkZjA9ZGF0YS5mcmFtZShjYmluZChwc2V1ZG90aW1lPXBEYXRhKGNkcykkUHNldWRvdGltZSxsb2cxcCh0KGNkc19leHBycykqbXR4X3NpemVmYWN0b3IpKSkKZGYwPWRhdGEuZnJhbWUoY2JpbmQocHNldWRvdGltZT1wRGF0YShjZHMpJFBzZXVkb3RpbWUsdChjZHNfZXhwcnMpKSkKZGYwJFVNQVBfMT1yZWR1Y2VkRGltcyhjZHMpJFVNQVBbLDFdCmRmMCRVTUFQXzI9cmVkdWNlZERpbXMoY2RzKSRVTUFQWywyXQpkZjAkQmF0Y2hJRD1wRGF0YShjZHMpJGRhdGFzZXRfYmF0Y2gKZGYwPWRmMFtpcy5maW5pdGUoZGYwJHBzZXVkb3RpbWUpLF0KZGYwPWRmMFtvcmRlcihkZjAkcHNldWRvdGltZSxkZWNyZWFzaW5nID0gRiksLGRyb3A9Rl0KZGYwJHg9ZGYwJHBzZXVkb3RpbWUvbWF4KGRmMCRwc2V1ZG90aW1lKQpkZl9wc2V1ZG90aW1lX2xpc3QkZGNhX2xhdGVudF9hbGw9ZGYwCmBgYAoKLSBGZWF0dXJlIHBsb3RzIG9mIGBGQ0dSM0FgIGFuZCBgUzEwMEE4YAoKYGBge3J9CnA9Z2V0X3Bsb3Q0KGRmMDAgPSBkZjApCmBgYAoKYGBge3IsIGZpZy5oZWlnaHQ9NCxmaWcud2lkdGg9MTh9CnAKYGBgCgpgYGB7cn0KZGZfZGVuPWNvbERhdGEoY2RzKQp0dDE9a3MudGVzdChkZl9kZW4kUHNldWRvdGltZVtkZl9kZW4kZGF0YXNldF9iYXRjaD09IlQxIl0sZGZfZGVuJFBzZXVkb3RpbWVbZGZfZGVuJGRhdGFzZXRfYmF0Y2g9PSJUMyJdKQp0dDEKdHQyPWtzLnRlc3QoZGZfZGVuJFBzZXVkb3RpbWVbZGZfZGVuJGRhdGFzZXRfYmF0Y2g9PSJUMSJdLGRmX2RlbiRQc2V1ZG90aW1lW2RmX2RlbiRkYXRhc2V0X2JhdGNoPT0iVDIiXSkKdHQyCnR0Mz1rcy50ZXN0KGRmX2RlbiRQc2V1ZG90aW1lW2RmX2RlbiRkYXRhc2V0X2JhdGNoPT0iVDIiXSxkZl9kZW4kUHNldWRvdGltZVtkZl9kZW4kZGF0YXNldF9iYXRjaD09IlQzIl0pCnR0MwpgYGAKCmBgYHtyfQpTdGFibGU1WzksMjo0XT1tYXRyaXgoZ2V0X3BfbmV3KGModHQxJHAudmFsdWUsdHQyJHAudmFsdWUsdHQzJHAudmFsdWUpLGModHQxJHN0YXRpc3RpYyx0dDIkc3RhdGlzdGljLHR0MyRzdGF0aXN0aWMpKSwxLDMpCmBgYAoKIyMgSFZHcyBkZW5vaXNlZAoKYGBge3J9CmNkcyA8LSBuZXdfY2VsbF9kYXRhX3NldChtdHhbcm93bmFtZXMobXR4KSVpbiVodmdfZ2VuZXMkZ2VuZW5hbWUsXSwgY2VsbF9tZXRhZGF0YSA9IGNlbGwubWV0YS5kYXRhLGdlbmVfbWV0YWRhdGEgPWdlbmVfYW5uW2dlbmVfYW5uJGdlbmVfc2hvcnRfbmFtZSVpbiVodmdfZ2VuZXMkZ2VuZW5hbWUsLGRyb3A9Rl0pCiMjIFN0ZXAgMTogTm9ybWFsaXplIGFuZCBwcmUtcHJvY2VzcyB0aGUgZGF0YQpjZHMgPC0gcHJlcHJvY2Vzc19jZHMoY2RzLCBudW1fZGltID0gMzIsbWV0aG9kPSJQQ0EiLG5vcm1fbWV0aG9kPSJsb2ciLHZlcmJvc2UgPSBGKQoKdG1wMD1weV90b19yKGFkYXRhJG9ic21bIlhfcGNhaHZnIl0pICNvcmlnaW5hbCBkY2EKY29sbmFtZXModG1wMCk9cGFzdGUwKCJQQyIsMTpuY29sKHRtcDApKQpyZWR1Y2VkRGltcyhjZHMpJFBDQT10bXAwCgoKIyMgU3RlcCAyOiBSZW1vdmUgYmF0Y2ggZWZmZWN0cyB3aXRoIGNlbGwgYWxpZ25tZW50CiMjY2RzIDwtIGFsaWduX2NkcyhjZHMsIGFsaWdubWVudF9ncm91cCA9ICJCYXRjaElEIiwgcmVzaWR1YWxfbW9kZWxfZm9ybXVsYV9zdHIgPSBOVUxMKQojIyBTdGVwIDM6IFJlZHVjZSB0aGUgZGltZW5zaW9ucyB1c2luZyBVTUFQCmNkcyA8LSByZWR1Y2VfZGltZW5zaW9uKGNkcyxyZWR1Y3Rpb25fbWV0aG9kID0gIlVNQVAiLHByZXByb2Nlc3NfbWV0aG9kPSJQQ0EiLHZlcmJvc2UgPSBGKQoKIyMgU3RlcCA0OiBDbHVzdGVyIHRoZSBjZWxscwpjZHMgPC0gY2x1c3Rlcl9jZWxscyhjZHMscmVkdWN0aW9uX21ldGhvZCA9IlVNQVAiLGNsdXN0ZXJfbWV0aG9kID0gImxlaWRlbiIsdmVyYm9zZSA9IEYpCgojIENvbnN0cnVjdCB0aGUgZ3JhcGgKIyBOb3RlIHRoYXQsIGZvciB0aGUgcmVzdCBvZiB0aGUgY29kZSB0byBydW4sIHRoZSBncmFwaCBzaG91bGQgYmUgZnVsbHkgKHBhcnRpb25seSkgY29ubmVjdGVkCiMjIFN0ZXAgNTogTGVhcm4gYSBncmFwaApjZHMgPC0gbGVhcm5fZ3JhcGgoY2RzLCB1c2VfcGFydGl0aW9uID0gVCx2ZXJib3NlID0gRikKY29sRGF0YShjZHMpJGNsdXN0ZXJzPWNkc0BjbHVzdGVycyRVTUFQJGNsdXN0ZXJzCnAxPXBsb3RfY2VsbHMoY2RzLGNvbG9yX2NlbGxzX2J5ID0gInBhcnRpdGlvbiIsbGFiZWxfY2VsbF9ncm91cHMgPSBGKSt0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIikKcDI9cGxvdF9jZWxscyhjZHMsY29sb3JfY2VsbHNfYnkgPSAiY2x1c3RlcnMiLGxhYmVsX2NlbGxfZ3JvdXBzPUYsZ3JhcGhfbGFiZWxfc2l6ZT0yLCBsYWJlbF9sZWF2ZXM9RixsYWJlbF9icmFuY2hfcG9pbnRzPUYpK3RoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiKQpwPWNvd3Bsb3Q6OnBsb3RfZ3JpZChwMSxwMixhbGlnbiA9ICJoIixuY29sID0gMykKYGBgCgpgYGB7ciBmaWcuaGVpZ2h0PTUsZmlnLndpZHRoPTE4fQpwCmBgYAoKYGBge3J9CiMjIFN0ZXAgNjogT3JkZXIgY2VsbHMKIyByb290IGNlbGxzCmlkcz1nZXRfZWFybGllc3RfcHJpbmNpcGFsX25vZGUoY2RzLGNsdXN0ZXI9YygiMSIsIjMiLCI0IikpCmNkcyA8LSBvcmRlcl9jZWxscyhjZHMsIHJvb3RfcHJfbm9kZXM9aWRzKQojcGxvdF9jZWxscyhjZHMsY29sb3JfY2VsbHNfYnkgPSAicHNldWRvdGltZSIpCmBgYAoKCmBgYHtyLGZpZy5oZWlnaHQ9NSxmaWcud2lkdGg9MTh9CmNvbERhdGEoY2RzKSRwc2V1ZG90aW1lPXBzZXVkb3RpbWUoY2RzKQpjb2xEYXRhKGNkcykkUHNldWRvdGltZT1jb2xEYXRhKGNkcykkcHNldWRvdGltZS9tYXgoY29sRGF0YShjZHMpJHBzZXVkb3RpbWUsbmEucm0gPSBUKQpkZl9kZW49cERhdGEoY2RzKVssYygiUHNldWRvdGltZSIsImRhdGFzZXRfYmF0Y2giKV0KZGZfZGVuPWFzLmRhdGEuZnJhbWUoZGZfZGVuWyFpcy5pbmZpbml0ZShkZl9kZW4kUHNldWRvdGltZSksXSkKc2V0LnNlZWQoMTApCgp0aGVtZV91c2U9dGhlbWUobGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT0xNiksCiAgICAgICAgICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT0yMCkpCgpwX2RjYV9kZW5vaXNlZF9odmdfMT1wbG90X2NlbGxzKGNkcyxjb2xvcl9jZWxsc19ieSA9ICJkYXRhc2V0X2JhdGNoIiwsZ3JhcGhfbGFiZWxfc2l6ZT0wLGFscGhhPTEsY2VsbF9zaXplID0gMC42KSsKICBndWlkZXMoY29sb3VyID0gZ3VpZGVfbGVnZW5kKG92ZXJyaWRlLmFlcyA9IGxpc3QoYWxwaGE9MC43LCBzaXplPTUpKSkrCiAgdGhlbWVfdXNlKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiKQogICAgICAgICAgCnBfZGNhX2Rlbm9pc2VkX2h2Z18yPXBsb3RfY2VsbHMoY2RzLGNvbG9yX2NlbGxzX2J5ID0gIlBzZXVkb3RpbWUiLGxhYmVsX2JyYW5jaF9wb2ludHM9VCxncmFwaF9sYWJlbF9zaXplPTIsYWxwaGE9MSxjZWxsX3NpemUgPSAwLjYpKwogICAgICAgICAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIiwKICAgICAgICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQodmp1c3QgPSAwLjIpLAogICAgICAgICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KGFuZ2xlPS01MCApLAogICAgICAgICAgICAgICAgICBsZWdlbmQua2V5LmhlaWdodCA9IHVuaXQoMC41LCJjbSIpLAogICAgICAgICAgICAgICAgICBsZWdlbmQua2V5LndpZHRoID0gdW5pdCgxLCJjbSIpKSsKICAgICAgICAgICAgZ3VpZGVzKGNvbG9yID0gZ3VpZGVfY29sb3VyYmFyKGxhYmVsLnBvc2l0aW9uID0gInRvcCIpKSt0aGVtZV91c2UKCnBfZGNhX2Rlbm9pc2VkX2h2Z18zPWdncGxvdChkYXRhPWRmX2RlbikrZ2VvbV9kZW5zaXR5KGFlcyh4PVBzZXVkb3RpbWUsZmlsbD1kYXRhc2V0X2JhdGNoKSxhbHBoYT0wLjcpKwogICAgICAgICAgICBzY2FsZV95X2NvbnRpbnVvdXMoZXhwYW5kID0gYygwLDApKSsKICAgICAgICAgICAgc2NhbGVfeF9jb250aW51b3VzKGV4cGFuZCA9IGMoMCwwKSkrCiAgICAgICAgICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0idG9wIikrdGhlbWVfdXNlCgpwX21vbm9jbGVfZGNhX2Rlbm9pc2VkX2h2Zz1lZ2c6OmdnYXJyYW5nZShwX2RjYV9kZW5vaXNlZF9odmdfMSxwX2RjYV9kZW5vaXNlZF9odmdfMixwX2RjYV9kZW5vaXNlZF9odmdfMyxuY29sPTMsZHJhdz1GKQpgYGAKCmBgYHtyIGZpZy5oZWlnaHQ9NSxmaWcud2lkdGg9MTh9CnBfbW9ub2NsZV9kY2FfZGVub2lzZWRfaHZnCmBgYAoKYGBge3J9CiNjZHNfZXhwcnM9RmV0Y2hEYXRhKG9iajAsdmFycyA9IGMoIkZDR1IzQSIsIlMxMDBBOCIpKQojZGYwPWRhdGEuZnJhbWUoY2JpbmQocHNldWRvdGltZT1wRGF0YShjZHMpJFBzZXVkb3RpbWUsY2RzX2V4cHJzKSkKY2RzX2V4cHJzPWFzLm1hdHJpeChTaW5nbGVDZWxsRXhwZXJpbWVudDo6Y291bnRzKGNkcylbYygiRkNHUjNBIiwiUzEwMEE4IiksXSkKZGYwPWRhdGEuZnJhbWUoY2JpbmQocHNldWRvdGltZT1wRGF0YShjZHMpJFBzZXVkb3RpbWUsdChjZHNfZXhwcnMpKSkKZGYwJFVNQVBfMT1yZWR1Y2VkRGltcyhjZHMpJFVNQVBbLDFdCmRmMCRVTUFQXzI9cmVkdWNlZERpbXMoY2RzKSRVTUFQWywyXQpkZjAkQmF0Y2hJRD1wRGF0YShjZHMpJGRhdGFzZXRfYmF0Y2gKZGYwPWRmMFtpcy5maW5pdGUoZGYwJHBzZXVkb3RpbWUpLF0KZGYwPWRmMFtvcmRlcihkZjAkcHNldWRvdGltZSxkZWNyZWFzaW5nID0gRiksLGRyb3A9Rl0KZGYwJHg9ZGYwJHBzZXVkb3RpbWUvbWF4KGRmMCRwc2V1ZG90aW1lKQpkZl9wc2V1ZG90aW1lX2xpc3QkZGNhX2Rlbm9pc2VkX2h2Zz1kZjAKYGBgCgotIEZlYXR1cmUgcGxvdHMgb2YgYEZDR1IzQWAgYW5kIGBTMTAwQThgCgpgYGB7cn0KcD1nZXRfcGxvdDQoZGYwMCA9IGRmMCkKYGBgCgpgYGB7ciwgZmlnLmhlaWdodD00LGZpZy53aWR0aD0xOH0KcApgYGAKCmBgYHtyfQpkZl9kZW49Y29sRGF0YShjZHMpCnR0MT1rcy50ZXN0KGRmX2RlbiRQc2V1ZG90aW1lW2RmX2RlbiRkYXRhc2V0X2JhdGNoPT0iVDEiXSxkZl9kZW4kUHNldWRvdGltZVtkZl9kZW4kZGF0YXNldF9iYXRjaD09IlQzIl0pCnR0MQp0dDI9a3MudGVzdChkZl9kZW4kUHNldWRvdGltZVtkZl9kZW4kZGF0YXNldF9iYXRjaD09IlQxIl0sZGZfZGVuJFBzZXVkb3RpbWVbZGZfZGVuJGRhdGFzZXRfYmF0Y2g9PSJUMiJdKQp0dDIKdHQzPWtzLnRlc3QoZGZfZGVuJFBzZXVkb3RpbWVbZGZfZGVuJGRhdGFzZXRfYmF0Y2g9PSJUMiJdLGRmX2RlbiRQc2V1ZG90aW1lW2RmX2RlbiRkYXRhc2V0X2JhdGNoPT0iVDMiXSkKdHQzCmBgYAoKYGBge3J9ClN0YWJsZTVbMTAsMjo0XT1tYXRyaXgoZ2V0X3BfbmV3KGModHQxJHAudmFsdWUsdHQyJHAudmFsdWUsdHQzJHAudmFsdWUpLGModHQxJHN0YXRpc3RpYyx0dDIkc3RhdGlzdGljLHR0MyRzdGF0aXN0aWMpKSwxLDMpCmBgYAoKIyMgQWxsIGdlbmVzIGRlbm9pc2VkCgpgYGB7cn0KY2RzIDwtIG5ld19jZWxsX2RhdGFfc2V0KG10eCwgY2VsbF9tZXRhZGF0YSA9IGNlbGwubWV0YS5kYXRhLGdlbmVfbWV0YWRhdGEgPWdlbmVfYW5uKQojIyBTdGVwIDE6IE5vcm1hbGl6ZSBhbmQgcHJlLXByb2Nlc3MgdGhlIGRhdGEKY2RzIDwtIHByZXByb2Nlc3NfY2RzKGNkcywgbnVtX2RpbSA9IDMyLG1ldGhvZD0iUENBIixub3JtX21ldGhvZD0ibG9nIix2ZXJib3NlID0gRikKCiMjIFN0ZXAgMjogUmVtb3ZlIGJhdGNoIGVmZmVjdHMgd2l0aCBjZWxsIGFsaWdubWVudAojI2NkcyA8LSBhbGlnbl9jZHMoY2RzLCBhbGlnbm1lbnRfZ3JvdXAgPSAiQmF0Y2hJRCIsIHJlc2lkdWFsX21vZGVsX2Zvcm11bGFfc3RyID0gTlVMTCkKIyMgU3RlcCAzOiBSZWR1Y2UgdGhlIGRpbWVuc2lvbnMgdXNpbmcgVU1BUApjZHMgPC0gcmVkdWNlX2RpbWVuc2lvbihjZHMscmVkdWN0aW9uX21ldGhvZCA9ICJVTUFQIixwcmVwcm9jZXNzX21ldGhvZD0iUENBIix2ZXJib3NlID0gRikKCnRtcDA9cHlfdG9fcihhZGF0YSRvYnNtWyJYX3BjYWFsbCJdKSAjb3JpZ2luYWwgZGNhCmNvbG5hbWVzKHRtcDApPXBhc3RlMCgiUEMiLDE6bmNvbCh0bXAwKSkKcmVkdWNlZERpbXMoY2RzKSRQQ0E9dG1wMAoKCiMjIFN0ZXAgNDogQ2x1c3RlciB0aGUgY2VsbHMKY2RzIDwtIGNsdXN0ZXJfY2VsbHMoY2RzLHJlZHVjdGlvbl9tZXRob2QgPSJVTUFQIixjbHVzdGVyX21ldGhvZCA9ICJsZWlkZW4iLHZlcmJvc2UgPSBGKQoKIyBDb25zdHJ1Y3QgdGhlIGdyYXBoCiMgTm90ZSB0aGF0LCBmb3IgdGhlIHJlc3Qgb2YgdGhlIGNvZGUgdG8gcnVuLCB0aGUgZ3JhcGggc2hvdWxkIGJlIGZ1bGx5IChwYXJ0aW9ubHkpIGNvbm5lY3RlZAojIyBTdGVwIDU6IExlYXJuIGEgZ3JhcGgKY2RzIDwtIGxlYXJuX2dyYXBoKGNkcywgdXNlX3BhcnRpdGlvbiA9IFQsdmVyYm9zZSA9IEYpCmNvbERhdGEoY2RzKSRjbHVzdGVycz1jZHNAY2x1c3RlcnMkVU1BUCRjbHVzdGVycwpwMT1wbG90X2NlbGxzKGNkcyxjb2xvcl9jZWxsc19ieSA9ICJwYXJ0aXRpb24iLGxhYmVsX2NlbGxfZ3JvdXBzID0gRikrdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIpCnAyPXBsb3RfY2VsbHMoY2RzLGNvbG9yX2NlbGxzX2J5ID0gImNsdXN0ZXJzIixsYWJlbF9jZWxsX2dyb3Vwcz1GLGdyYXBoX2xhYmVsX3NpemU9MiwgbGFiZWxfbGVhdmVzPUYsbGFiZWxfYnJhbmNoX3BvaW50cz1GKSt0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIikKcD1jb3dwbG90OjpwbG90X2dyaWQocDEscDIsYWxpZ24gPSAiaCIsbmNvbCA9IDMpCmBgYAoKYGBge3IsIGZpZy5oZWlnaHQ9NSxmaWcud2lkdGg9MTh9CnAKYGBgCgpgYGB7cn0KIyMgU3RlcCA2OiBPcmRlciBjZWxscwojIHJvb3QgY2VsbHMKaWRzPWdldF9lYXJsaWVzdF9wcmluY2lwYWxfbm9kZShjZHMsY2x1c3Rlcj1jKCIyIiwiNCIsIjUiKSkKY2RzIDwtIG9yZGVyX2NlbGxzKGNkcywgcm9vdF9wcl9ub2Rlcz1pZHMpCiNwbG90X2NlbGxzKGNkcyxjb2xvcl9jZWxsc19ieSA9ICJwc2V1ZG90aW1lIikKYGBgCgoKYGBge3IsZmlnLmhlaWdodD01LGZpZy53aWR0aD0xOH0KY29sRGF0YShjZHMpJHBzZXVkb3RpbWU9cHNldWRvdGltZShjZHMpCmNvbERhdGEoY2RzKSRQc2V1ZG90aW1lPWNvbERhdGEoY2RzKSRwc2V1ZG90aW1lL21heChjb2xEYXRhKGNkcykkcHNldWRvdGltZSxuYS5ybSA9IFQpCmRmX2Rlbj1wRGF0YShjZHMpWyxjKCJQc2V1ZG90aW1lIiwiZGF0YXNldF9iYXRjaCIpXQpkZl9kZW49YXMuZGF0YS5mcmFtZShkZl9kZW5bIWlzLmluZmluaXRlKGRmX2RlbiRQc2V1ZG90aW1lKSxdKQpzZXQuc2VlZCgxMCkKCnRoZW1lX3VzZT10aGVtZShsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTE2KSwKICAgICAgICAgICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTIwKSkKCnBfZGNhX2Rlbm9pc2VkX2FsbF8xPXBsb3RfY2VsbHMoY2RzLGNvbG9yX2NlbGxzX2J5ID0gImRhdGFzZXRfYmF0Y2giLCxncmFwaF9sYWJlbF9zaXplPTAsYWxwaGE9MSxjZWxsX3NpemUgPSAwLjYpKwogIGd1aWRlcyhjb2xvdXIgPSBndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID0gbGlzdChhbHBoYT0wLjcsIHNpemU9NSkpKSsKICB0aGVtZV91c2UrCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIpCiAgICAgICAgICAKcF9kY2FfZGVub2lzZWRfYWxsXzI9cGxvdF9jZWxscyhjZHMsY29sb3JfY2VsbHNfYnkgPSAiUHNldWRvdGltZSIsbGFiZWxfYnJhbmNoX3BvaW50cz1ULGdyYXBoX2xhYmVsX3NpemU9MixhbHBoYT0xLGNlbGxfc2l6ZSA9IDAuNikrCiAgICAgICAgICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiLAogICAgICAgICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dCh2anVzdCA9IDAuMiksCiAgICAgICAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoYW5nbGU9LTUwICksCiAgICAgICAgICAgICAgICAgIGxlZ2VuZC5rZXkuaGVpZ2h0ID0gdW5pdCgwLjUsImNtIiksCiAgICAgICAgICAgICAgICAgIGxlZ2VuZC5rZXkud2lkdGggPSB1bml0KDEsImNtIikpKwogICAgICAgICAgICBndWlkZXMoY29sb3IgPSBndWlkZV9jb2xvdXJiYXIobGFiZWwucG9zaXRpb24gPSAidG9wIikpK3RoZW1lX3VzZQoKcF9kY2FfZGVub2lzZWRfYWxsXzM9Z2dwbG90KGRhdGE9ZGZfZGVuKStnZW9tX2RlbnNpdHkoYWVzKHg9UHNldWRvdGltZSxmaWxsPWRhdGFzZXRfYmF0Y2gpLGFscGhhPTAuNykrCiAgICAgICAgICAgIHNjYWxlX3lfY29udGludW91cyhleHBhbmQgPSBjKDAsMCkpKwogICAgICAgICAgICBzY2FsZV94X2NvbnRpbnVvdXMoZXhwYW5kID0gYygwLDApKSsKICAgICAgICAgICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJ0b3AiKSt0aGVtZV91c2UKCnBfbW9ub2NsZV9kY2FfZGVub2lzZWRfYWxsPWVnZzo6Z2dhcnJhbmdlKHBfZGNhX2Rlbm9pc2VkX2FsbF8xLHBfZGNhX2Rlbm9pc2VkX2FsbF8yLHBfZGNhX2Rlbm9pc2VkX2FsbF8zLG5jb2w9MyxkcmF3PUYpCmBgYAoKYGBge3IsIGZpZy5oZWlnaHQ9NSxmaWcud2lkdGg9MTh9CnBfbW9ub2NsZV9kY2FfZGVub2lzZWRfYWxsCmBgYAoKYGBge3J9CiNjZHNfZXhwcnM9RmV0Y2hEYXRhKG9iajAsdmFycyA9IGMoIkZDR1IzQSIsIlMxMDBBOCIpKQojZGYwPWRhdGEuZnJhbWUoY2JpbmQocHNldWRvdGltZT1wRGF0YShjZHMpJFBzZXVkb3RpbWUsY2RzX2V4cHJzKSkKY2RzX2V4cHJzPWFzLm1hdHJpeChTaW5nbGVDZWxsRXhwZXJpbWVudDo6Y291bnRzKGNkcylbYygiRkNHUjNBIiwiUzEwMEE4IiksXSkKI2RmMD1kYXRhLmZyYW1lKGNiaW5kKHBzZXVkb3RpbWU9cERhdGEoY2RzKSRQc2V1ZG90aW1lLGxvZzFwKHQoY2RzX2V4cHJzKSptdHhfc2l6ZWZhY3RvcikpKQpkZjA9ZGF0YS5mcmFtZShjYmluZChwc2V1ZG90aW1lPXBEYXRhKGNkcykkUHNldWRvdGltZSx0KGNkc19leHBycykpKQpkZjAkVU1BUF8xPXJlZHVjZWREaW1zKGNkcykkVU1BUFssMV0KZGYwJFVNQVBfMj1yZWR1Y2VkRGltcyhjZHMpJFVNQVBbLDJdCmRmMCRCYXRjaElEPXBEYXRhKGNkcykkZGF0YXNldF9iYXRjaApkZjA9ZGYwW2lzLmZpbml0ZShkZjAkcHNldWRvdGltZSksXQpkZjA9ZGYwW29yZGVyKGRmMCRwc2V1ZG90aW1lLGRlY3JlYXNpbmcgPSBGKSwsZHJvcD1GXQpkZjAkeD1kZjAkcHNldWRvdGltZS9tYXgoZGYwJHBzZXVkb3RpbWUpCmRmX3BzZXVkb3RpbWVfbGlzdCRkY2FfZGVub2lzZWRfYWxsPWRmMApgYGAKCi0gRmVhdHVyZSBwbG90cyBvZiBgRkNHUjNBYCBhbmQgYFMxMDBBOGAKCmBgYHtyfQpwPWdldF9wbG90NChkZjAwID0gZGYwKQpgYGAKCmBgYHtyLCBmaWcuaGVpZ2h0PTQsZmlnLndpZHRoPTE4fQpwCmBgYAoKYGBge3J9CmRmX2Rlbj1jb2xEYXRhKGNkcykKdHQxPWtzLnRlc3QoZGZfZGVuJFBzZXVkb3RpbWVbZGZfZGVuJGRhdGFzZXRfYmF0Y2g9PSJUMSJdLGRmX2RlbiRQc2V1ZG90aW1lW2RmX2RlbiRkYXRhc2V0X2JhdGNoPT0iVDMiXSkKdHQxCnR0Mj1rcy50ZXN0KGRmX2RlbiRQc2V1ZG90aW1lW2RmX2RlbiRkYXRhc2V0X2JhdGNoPT0iVDEiXSxkZl9kZW4kUHNldWRvdGltZVtkZl9kZW4kZGF0YXNldF9iYXRjaD09IlQyIl0pCnR0Mgp0dDM9a3MudGVzdChkZl9kZW4kUHNldWRvdGltZVtkZl9kZW4kZGF0YXNldF9iYXRjaD09IlQyIl0sZGZfZGVuJFBzZXVkb3RpbWVbZGZfZGVuJGRhdGFzZXRfYmF0Y2g9PSJUMyJdKQp0dDMKYGBgCgpgYGB7cn0KU3RhYmxlNVsxMSwyOjRdPW1hdHJpeChnZXRfcF9uZXcoYyh0dDEkcC52YWx1ZSx0dDIkcC52YWx1ZSx0dDMkcC52YWx1ZSksYyh0dDEkc3RhdGlzdGljLHR0MiRzdGF0aXN0aWMsdHQzJHN0YXRpc3RpYykpLDEsMykKYGBgCgoKIyBNb25vY2xlMyB1c2luZyBNTk4KCmBgYHtyfQpvdXRwdXQ9cmVhZFJEUygiLi4vZmluYWxfcHJvY2Vzc2VkX3Jlc3VsdHMvTU5OX2NvcnJlY3RlZF9hbGwucmRzIikKbXR4PW91dHB1dEBhc3NheXMkZGF0YSRjb3JyZWN0ZWQKY2VsbC5tZXRhLmRhdGE9Y29sRGF0YShvdXRwdXQpCmNlbGwubWV0YS5kYXRhJGRhdGFzZXRfYmF0Y2g9cGx5cjo6bWFwdmFsdWVzKGNlbGwubWV0YS5kYXRhJGJhdGNoX2xhYmVsLG5hbWVzKG1hcHJ1bGVzKSxtYXBydWxlcykKZ2VuZV9hbm49ZGF0YS5mcmFtZShnZW5lX3Nob3J0X25hbWUgPSBtYWtlLnVuaXF1ZShyb3duYW1lcyhtdHgpKSwKICAgICAgICAgICAgICAgICAgICByb3cubmFtZXMgPSBtYWtlLnVuaXF1ZShyb3duYW1lcyhtdHgpKSkKCmBgYAoKIyMjIEhWR3MgZGVub2lzZWQKCmBgYHtyfQojbXR4PW10eFtnZW5lX2FubiRWYXJpYW5jZVR5cGU9PSJIVkciLF0KY2RzIDwtIG5ld19jZWxsX2RhdGFfc2V0KG10eFtyb3duYW1lcyhtdHgpJWluJWh2Z19nZW5lcyRnZW5lbmFtZSxdLCAKICAgICAgICAgICAgICAgICAgICAgICAgIGNlbGxfbWV0YWRhdGEgPSBjZWxsLm1ldGEuZGF0YSwKICAgICAgICAgICAgICAgICAgICAgICAgIGdlbmVfbWV0YWRhdGEgPWdlbmVfYW5uW2dlbmVfYW5uJGdlbmVfc2hvcnRfbmFtZSVpbiVodmdfZ2VuZXMkZ2VuZW5hbWUsLGRyb3A9Rl0pCiMjIFN0ZXAKIyMgU3RlcCAxOiBOb3JtYWxpemUgYW5kIHByZS1wcm9jZXNzIHRoZSBkYXRhCmNkcyA8LSBwcmVwcm9jZXNzX2NkcyhjZHMsIG51bV9kaW0gPSAzMixtZXRob2Q9IlBDQSIsbm9ybV9tZXRob2Q9ImxvZyIpCiN0bXAwPXB5X3RvX3IoYWRhdGEkb2JzbVsiWF9kY2FfbGF0ZW50Il0pCiNjb2xuYW1lcyh0bXAwKT1wYXN0ZTAoIlBDIiwxOm5jb2wodG1wMCkpCiNyZWR1Y2VkRGltcyhjZHMpJFBDQT10bXAwCgojIyBTdGVwIDI6IFJlbW92ZSBiYXRjaCBlZmZlY3RzIHdpdGggY2VsbCBhbGlnbm1lbnQKIyNjZHMgPC0gYWxpZ25fY2RzKGNkcywgYWxpZ25tZW50X2dyb3VwID0gIkJhdGNoSUQiLCByZXNpZHVhbF9tb2RlbF9mb3JtdWxhX3N0ciA9IE5VTEwpCiMjIFN0ZXAgMzogUmVkdWNlIHRoZSBkaW1lbnNpb25zIHVzaW5nIFVNQVAKY2RzIDwtIHJlZHVjZV9kaW1lbnNpb24oY2RzLHJlZHVjdGlvbl9tZXRob2QgPSAiVU1BUCIscHJlcHJvY2Vzc19tZXRob2Q9IlBDQSIpCgojIyBTdGVwIDQ6IENsdXN0ZXIgdGhlIGNlbGxzCmNkcyA8LSBjbHVzdGVyX2NlbGxzKGNkcyxyZWR1Y3Rpb25fbWV0aG9kID0iVU1BUCIsY2x1c3Rlcl9tZXRob2QgPSAibGVpZGVuIikKCiMgQ29uc3RydWN0IHRoZSBncmFwaAojIE5vdGUgdGhhdCwgZm9yIHRoZSByZXN0IG9mIHRoZSBjb2RlIHRvIHJ1biwgdGhlIGdyYXBoIHNob3VsZCBiZSBmdWxseSAocGFydGlvbmx5KSBjb25uZWN0ZWQKIyMgU3RlcCA1OiBMZWFybiBhIGdyYXBoCmNkcyA8LSBsZWFybl9ncmFwaChjZHMsIHVzZV9wYXJ0aXRpb24gPSBULHZlcmJvc2UgPSBGKQpjb2xEYXRhKGNkcykkY2x1c3RlcnM9Y2RzQGNsdXN0ZXJzJFVNQVAkY2x1c3RlcnMKcDE9cGxvdF9jZWxscyhjZHMsY29sb3JfY2VsbHNfYnkgPSAicGFydGl0aW9uIixsYWJlbF9jZWxsX2dyb3VwcyA9IEYpK3RoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiKQpwMj1wbG90X2NlbGxzKGNkcyxjb2xvcl9jZWxsc19ieSA9ICJjbHVzdGVycyIsbGFiZWxfY2VsbF9ncm91cHM9RixncmFwaF9sYWJlbF9zaXplPTIsIGxhYmVsX2xlYXZlcz1GLGxhYmVsX2JyYW5jaF9wb2ludHM9RikrdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIpCnA9Y293cGxvdDo6cGxvdF9ncmlkKHAxLHAyLGFsaWduID0gImgiLG5jb2wgPSAzKQpgYGAKCmBgYHtyLCBmaWcuaGVpZ2h0PTUsZmlnLndpZHRoPTE4fQpwCmBgYAoKYGBge3J9CiMjIFN0ZXAgNjogT3JkZXIgY2VsbHMKIyByb290IGNlbGxzCmlkcz1nZXRfZWFybGllc3RfcHJpbmNpcGFsX25vZGUoY2RzLGNsdXN0ZXI9YygiMiIsIjMiLCI0IikpCmNkcyA8LSBvcmRlcl9jZWxscyhjZHMsIHJvb3RfcHJfbm9kZXM9aWRzKQojcGxvdF9jZWxscyhjZHMsY29sb3JfY2VsbHNfYnkgPSAicHNldWRvdGltZSIpCmBgYAoKCmBgYHtyLGZpZy5oZWlnaHQ9NSxmaWcud2lkdGg9MTh9CmNvbERhdGEoY2RzKSRwc2V1ZG90aW1lPXBzZXVkb3RpbWUoY2RzKQpjb2xEYXRhKGNkcykkUHNldWRvdGltZT1jb2xEYXRhKGNkcykkcHNldWRvdGltZS9tYXgoY29sRGF0YShjZHMpJHBzZXVkb3RpbWUsbmEucm0gPSBUKQojc2F2ZVJEUyhjZHMsZmlsZT0iY2RzX21ubi5yZHMiKQpkZl9kZW49cERhdGEoY2RzKVssYygiUHNldWRvdGltZSIsImRhdGFzZXRfYmF0Y2giKV0KZGZfZGVuPWFzLmRhdGEuZnJhbWUoZGZfZGVuWyFpcy5pbmZpbml0ZShkZl9kZW4kUHNldWRvdGltZSksXSkKc2V0LnNlZWQoMTApCgp0aGVtZV91c2U9dGhlbWUobGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT0xNiksCiAgICAgICAgICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT0yMCkpCgpwX21ubl9kZW5vaXNlZF9odmdfMT1wbG90X2NlbGxzKGNkcyxjb2xvcl9jZWxsc19ieSA9ICJkYXRhc2V0X2JhdGNoIiwsZ3JhcGhfbGFiZWxfc2l6ZT0wLGFscGhhPTEsY2VsbF9zaXplID0gMC42KSsKICBndWlkZXMoY29sb3VyID0gZ3VpZGVfbGVnZW5kKG92ZXJyaWRlLmFlcyA9IGxpc3QoYWxwaGE9MC43LCBzaXplPTUpKSkrCiAgdGhlbWVfdXNlKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiKQogICAgICAgICAgCnBfbW5uX2Rlbm9pc2VkX2h2Z18yPXBsb3RfY2VsbHMoY2RzLGNvbG9yX2NlbGxzX2J5ID0gIlBzZXVkb3RpbWUiLGxhYmVsX2JyYW5jaF9wb2ludHM9VCxncmFwaF9sYWJlbF9zaXplPTIsYWxwaGE9MSxjZWxsX3NpemUgPSAwLjYpKwogICAgICAgICAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIiwKICAgICAgICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQodmp1c3QgPSAwLjIpLAogICAgICAgICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KGFuZ2xlPS01MCApLAogICAgICAgICAgICAgICAgICBsZWdlbmQua2V5LmhlaWdodCA9IHVuaXQoMC41LCJjbSIpLAogICAgICAgICAgICAgICAgICBsZWdlbmQua2V5LndpZHRoID0gdW5pdCgxLCJjbSIpKSsKICAgICAgICAgICAgZ3VpZGVzKGNvbG9yID0gZ3VpZGVfY29sb3VyYmFyKGxhYmVsLnBvc2l0aW9uID0gInRvcCIpKSt0aGVtZV91c2UKCnBfbW5uX2Rlbm9pc2VkX2h2Z18zPWdncGxvdChkYXRhPWRmX2RlbikrZ2VvbV9kZW5zaXR5KGFlcyh4PVBzZXVkb3RpbWUsZmlsbD1kYXRhc2V0X2JhdGNoKSxhbHBoYT0wLjcpKwogICAgICAgICAgICBzY2FsZV95X2NvbnRpbnVvdXMoZXhwYW5kID0gYygwLDApKSsKICAgICAgICAgICAgc2NhbGVfeF9jb250aW51b3VzKGV4cGFuZCA9IGMoMCwwKSkrCiAgICAgICAgICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0idG9wIikrdGhlbWVfdXNlCgpwX21vbm9jbGVfbW5uX2Rlbm9pc2VkX2h2Zz1lZ2c6OmdnYXJyYW5nZShwX21ubl9kZW5vaXNlZF9odmdfMSxwX21ubl9kZW5vaXNlZF9odmdfMixwX21ubl9kZW5vaXNlZF9odmdfMyxuY29sPTMsZHJhdz1GKQpgYGAKCmBgYHtyLCBmaWcuaGVpZ2h0PTUsZmlnLndpZHRoPTE4fQpwX21vbm9jbGVfbW5uX2Rlbm9pc2VkX2h2ZwpgYGAKCmBgYHtyfQojY2RzX2V4cHJzPUZldGNoRGF0YShvYmowLHZhcnMgPSBjKCJGQ0dSM0EiLCJTMTAwQTgiKSkKI2RmMD1kYXRhLmZyYW1lKGNiaW5kKHBzZXVkb3RpbWU9cERhdGEoY2RzKSRQc2V1ZG90aW1lLGNkc19leHBycykpCmNkc19leHBycz1hcy5tYXRyaXgoU2luZ2xlQ2VsbEV4cGVyaW1lbnQ6OmNvdW50cyhjZHMpW2MoIkZDR1IzQSIsIlMxMDBBOCIpLF0pCmRmMD1kYXRhLmZyYW1lKGNiaW5kKHBzZXVkb3RpbWU9cERhdGEoY2RzKSRQc2V1ZG90aW1lLHQoY2RzX2V4cHJzKSptdHhfc2l6ZWZhY3RvcikpCmRmMCRVTUFQXzE9cmVkdWNlZERpbXMoY2RzKSRVTUFQWywxXQpkZjAkVU1BUF8yPXJlZHVjZWREaW1zKGNkcykkVU1BUFssMl0KZGYwJEJhdGNoSUQ9cERhdGEoY2RzKSRkYXRhc2V0X2JhdGNoCmRmMD1kZjBbaXMuZmluaXRlKGRmMCRwc2V1ZG90aW1lKSxdCmRmMD1kZjBbb3JkZXIoZGYwJHBzZXVkb3RpbWUsZGVjcmVhc2luZyA9IEYpLCxkcm9wPUZdCmRmMCR4PWRmMCRwc2V1ZG90aW1lL21heChkZjAkcHNldWRvdGltZSkKZGZfcHNldWRvdGltZV9saXN0JG1ubl9kZW5vaXNlZF9odmc9ZGYwCmBgYAoKLSBGZWF0dXJlIHBsb3RzIG9mIGBGQ0dSM0FgIGFuZCBgUzEwMEE4YAoKYGBge3J9CnA9Z2V0X3Bsb3Q0KGRmMDAgPSBkZjApCmBgYAoKYGBge3IsIGZpZy5oZWlnaHQ9NCxmaWcud2lkdGg9MTh9CnAKYGBgCgpgYGB7cn0KZGZfZGVuPWNvbERhdGEoY2RzKQp0dDE9a3MudGVzdChkZl9kZW4kUHNldWRvdGltZVtkZl9kZW4kZGF0YXNldF9iYXRjaD09IlQxIl0sZGZfZGVuJFBzZXVkb3RpbWVbZGZfZGVuJGRhdGFzZXRfYmF0Y2g9PSJUMyJdKQp0dDEKdHQyPWtzLnRlc3QoZGZfZGVuJFBzZXVkb3RpbWVbZGZfZGVuJGRhdGFzZXRfYmF0Y2g9PSJUMSJdLGRmX2RlbiRQc2V1ZG90aW1lW2RmX2RlbiRkYXRhc2V0X2JhdGNoPT0iVDIiXSkKdHQyCnR0Mz1rcy50ZXN0KGRmX2RlbiRQc2V1ZG90aW1lW2RmX2RlbiRkYXRhc2V0X2JhdGNoPT0iVDIiXSxkZl9kZW4kUHNldWRvdGltZVtkZl9kZW4kZGF0YXNldF9iYXRjaD09IlQzIl0pCnR0MwpgYGAKCmBgYHtyfQpTdGFibGU1WzEyLDI6NF09bWF0cml4KGdldF9wX25ldyhjKHR0MSRwLnZhbHVlLHR0MiRwLnZhbHVlLHR0MyRwLnZhbHVlKSxjKHR0MSRzdGF0aXN0aWMsdHQyJHN0YXRpc3RpYyx0dDMkc3RhdGlzdGljKSksMSwzKQpgYGAKCgojIyMgQWxsIGdlbmVzIGRlbm9pc2VkCgpgYGB7cn0Kb3V0cHV0PXJlYWRSRFMoIi4uL2ZpbmFsX3Byb2Nlc3NlZF9yZXN1bHRzL01OTl9jb3JyZWN0ZWRfYWxsLnJkcyIpCm10eD1vdXRwdXRAYXNzYXlzJGRhdGEkY29ycmVjdGVkCgpjZWxsLm1ldGEuZGF0YT1jb2xEYXRhKG91dHB1dCkKY2VsbC5tZXRhLmRhdGEkZGF0YXNldF9iYXRjaD1wbHlyOjptYXB2YWx1ZXMoY2VsbC5tZXRhLmRhdGEkYmF0Y2hfbGFiZWwsbmFtZXMobWFwcnVsZXMpLG1hcHJ1bGVzKQpnZW5lX2Fubj1kYXRhLmZyYW1lKGdlbmVfc2hvcnRfbmFtZSA9IG1ha2UudW5pcXVlKHJvd25hbWVzKG10eCkpLAogICAgICAgICAgICAgICAgICAgIHJvdy5uYW1lcyA9IG1ha2UudW5pcXVlKHJvd25hbWVzKG10eCkpKQoKI2NvbG5hbWVzKG10eCk9Y29sRGF0YShvdXRwdXQpJGNlbGxuYW1lCiNyb3duYW1lcyhtdHgpPXJvd25hbWVzKGdlbmVfYW5uKQojbXR4X3NpemVmYWN0b3I9MWU0L2NvbFN1bXMobXR4KQpgYGAKCmBgYHtyfQojbXR4PW10eFtnZW5lX2FubiRWYXJpYW5jZVR5cGU9PSJIVkciLF0KY2RzIDwtIG5ld19jZWxsX2RhdGFfc2V0KG10eCwgY2VsbF9tZXRhZGF0YSA9IGNlbGwubWV0YS5kYXRhLGdlbmVfbWV0YWRhdGEgPWdlbmVfYW5uKQojIyBTdGVwIDE6IE5vcm1hbGl6ZSBhbmQgcHJlLXByb2Nlc3MgdGhlIGRhdGEKY2RzIDwtIHByZXByb2Nlc3NfY2RzKGNkcywgbnVtX2RpbSA9IDMyLG1ldGhvZD0iUENBIixub3JtX21ldGhvZD0ibG9nIikKI3RtcDA9cHlfdG9fcihhZGF0YSRvYnNtWyJYX2RjYV9sYXRlbnQiXSkKI2NvbG5hbWVzKHRtcDApPXBhc3RlMCgiUEMiLDE6bmNvbCh0bXAwKSkKI3JlZHVjZWREaW1zKGNkcykkUENBPXRtcDAKCiMjIFN0ZXAgMjogUmVtb3ZlIGJhdGNoIGVmZmVjdHMgd2l0aCBjZWxsIGFsaWdubWVudAojI2NkcyA8LSBhbGlnbl9jZHMoY2RzLCBhbGlnbm1lbnRfZ3JvdXAgPSAiQmF0Y2hJRCIsIHJlc2lkdWFsX21vZGVsX2Zvcm11bGFfc3RyID0gTlVMTCkKIyMgU3RlcCAzOiBSZWR1Y2UgdGhlIGRpbWVuc2lvbnMgdXNpbmcgVU1BUApjZHMgPC0gcmVkdWNlX2RpbWVuc2lvbihjZHMscmVkdWN0aW9uX21ldGhvZCA9ICJVTUFQIixwcmVwcm9jZXNzX21ldGhvZD0iUENBIikKCiMjIFN0ZXAgNDogQ2x1c3RlciB0aGUgY2VsbHMKY2RzIDwtIGNsdXN0ZXJfY2VsbHMoY2RzLHJlZHVjdGlvbl9tZXRob2QgPSJVTUFQIixjbHVzdGVyX21ldGhvZCA9ICJsZWlkZW4iKQoKIyBDb25zdHJ1Y3QgdGhlIGdyYXBoCiMgTm90ZSB0aGF0LCBmb3IgdGhlIHJlc3Qgb2YgdGhlIGNvZGUgdG8gcnVuLCB0aGUgZ3JhcGggc2hvdWxkIGJlIGZ1bGx5IChwYXJ0aW9ubHkpIGNvbm5lY3RlZAojIyBTdGVwIDU6IExlYXJuIGEgZ3JhcGgKY2RzIDwtIGxlYXJuX2dyYXBoKGNkcywgdXNlX3BhcnRpdGlvbiA9IFQsdmVyYm9zZSA9IEYpCmNvbERhdGEoY2RzKSRjbHVzdGVycz1jZHNAY2x1c3RlcnMkVU1BUCRjbHVzdGVycwpwMT1wbG90X2NlbGxzKGNkcyxjb2xvcl9jZWxsc19ieSA9ICJwYXJ0aXRpb24iLGxhYmVsX2NlbGxfZ3JvdXBzID0gRikrdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIpCnAyPXBsb3RfY2VsbHMoY2RzLGNvbG9yX2NlbGxzX2J5ID0gImNsdXN0ZXJzIixsYWJlbF9jZWxsX2dyb3Vwcz1GLGdyYXBoX2xhYmVsX3NpemU9MiwgbGFiZWxfbGVhdmVzPUYsbGFiZWxfYnJhbmNoX3BvaW50cz1GKSt0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIikKcD1jb3dwbG90OjpwbG90X2dyaWQocDEscDIsYWxpZ24gPSAiaCIsbmNvbCA9IDMpCmBgYAoKYGBge3IsIGZpZy5oZWlnaHQ9NSxmaWcud2lkdGg9MTh9CnAKYGBgCgpgYGB7cn0KIyMgU3RlcCA2OiBPcmRlciBjZWxscwojIHJvb3QgY2VsbHMKaWRzPWdldF9lYXJsaWVzdF9wcmluY2lwYWxfbm9kZShjZHMsY2x1c3Rlcj1jKCI2IiwiMyIsIjUiKSkKY2RzIDwtIG9yZGVyX2NlbGxzKGNkcywgcm9vdF9wcl9ub2Rlcz1pZHMpCiNwbG90X2NlbGxzKGNkcyxjb2xvcl9jZWxsc19ieSA9ICJwc2V1ZG90aW1lIikKYGBgCgoKYGBge3IsZmlnLmhlaWdodD01LGZpZy53aWR0aD0xOH0KY29sRGF0YShjZHMpJHBzZXVkb3RpbWU9cHNldWRvdGltZShjZHMpCmNvbERhdGEoY2RzKSRQc2V1ZG90aW1lPWNvbERhdGEoY2RzKSRwc2V1ZG90aW1lL21heChjb2xEYXRhKGNkcykkcHNldWRvdGltZSxuYS5ybSA9IFQpCmRmX2Rlbj1wRGF0YShjZHMpWyxjKCJQc2V1ZG90aW1lIiwiZGF0YXNldF9iYXRjaCIpXQpkZl9kZW49YXMuZGF0YS5mcmFtZShkZl9kZW5bIWlzLmluZmluaXRlKGRmX2RlbiRQc2V1ZG90aW1lKSxdKQpzZXQuc2VlZCgxMCkKCnRoZW1lX3VzZT10aGVtZShsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTE2KSwKICAgICAgICAgICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTIwKSkKCnBfbW5uX2Rlbm9pc2VkX2FsbF8xPXBsb3RfY2VsbHMoY2RzLGNvbG9yX2NlbGxzX2J5ID0gImRhdGFzZXRfYmF0Y2giLCxncmFwaF9sYWJlbF9zaXplPTAsYWxwaGE9MSxjZWxsX3NpemUgPSAwLjYpKwogIGd1aWRlcyhjb2xvdXIgPSBndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID0gbGlzdChhbHBoYT0wLjcsIHNpemU9NSkpKSsKICB0aGVtZV91c2UrCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIpCiAgICAgICAgICAKcF9tbm5fZGVub2lzZWRfYWxsXzI9cGxvdF9jZWxscyhjZHMsY29sb3JfY2VsbHNfYnkgPSAiUHNldWRvdGltZSIsbGFiZWxfYnJhbmNoX3BvaW50cz1ULGdyYXBoX2xhYmVsX3NpemU9MixhbHBoYT0xLGNlbGxfc2l6ZSA9IDAuNikrCiAgICAgICAgICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiLAogICAgICAgICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dCh2anVzdCA9IDAuMiksCiAgICAgICAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoYW5nbGU9LTUwICksCiAgICAgICAgICAgICAgICAgIGxlZ2VuZC5rZXkuaGVpZ2h0ID0gdW5pdCgwLjUsImNtIiksCiAgICAgICAgICAgICAgICAgIGxlZ2VuZC5rZXkud2lkdGggPSB1bml0KDEsImNtIikpKwogICAgICAgICAgICBndWlkZXMoY29sb3IgPSBndWlkZV9jb2xvdXJiYXIobGFiZWwucG9zaXRpb24gPSAidG9wIikpK3RoZW1lX3VzZQoKcF9tbm5fZGVub2lzZWRfYWxsXzM9Z2dwbG90KGRhdGE9ZGZfZGVuKStnZW9tX2RlbnNpdHkoYWVzKHg9UHNldWRvdGltZSxmaWxsPWRhdGFzZXRfYmF0Y2gpLGFscGhhPTAuNykrCiAgICAgICAgICAgIHNjYWxlX3lfY29udGludW91cyhleHBhbmQgPSBjKDAsMCkpKwogICAgICAgICAgICBzY2FsZV94X2NvbnRpbnVvdXMoZXhwYW5kID0gYygwLDApKSsKICAgICAgICAgICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJ0b3AiKSt0aGVtZV91c2UKCnBfbW9ub2NsZV9tbm5fZGVub2lzZWRfYWxsPWVnZzo6Z2dhcnJhbmdlKHBfbW5uX2Rlbm9pc2VkX2FsbF8xLHBfbW5uX2Rlbm9pc2VkX2FsbF8yLHBfbW5uX2Rlbm9pc2VkX2FsbF8zLG5jb2w9MyxkcmF3PUYpCmBgYAoKYGBge3IsIGZpZy5oZWlnaHQ9NSxmaWcud2lkdGg9MTh9CnBfbW9ub2NsZV9tbm5fZGVub2lzZWRfYWxsCmBgYAoKYGBge3J9CiNjZHNfZXhwcnM9RmV0Y2hEYXRhKG9iajAsdmFycyA9IGMoIkZDR1IzQSIsIlMxMDBBOCIpKQojZGYwPWRhdGEuZnJhbWUoY2JpbmQocHNldWRvdGltZT1wRGF0YShjZHMpJFBzZXVkb3RpbWUsY2RzX2V4cHJzKSkKY2RzX2V4cHJzPWFzLm1hdHJpeChTaW5nbGVDZWxsRXhwZXJpbWVudDo6Y291bnRzKGNkcylbYygiRkNHUjNBIiwiUzEwMEE4IiksXSkKZGYwPWRhdGEuZnJhbWUoY2JpbmQocHNldWRvdGltZT1wRGF0YShjZHMpJFBzZXVkb3RpbWUsdChjZHNfZXhwcnMpKm10eF9zaXplZmFjdG9yKSkKZGYwJFVNQVBfMT1yZWR1Y2VkRGltcyhjZHMpJFVNQVBbLDFdCmRmMCRVTUFQXzI9cmVkdWNlZERpbXMoY2RzKSRVTUFQWywyXQpkZjAkQmF0Y2hJRD1wRGF0YShjZHMpJGRhdGFzZXRfYmF0Y2gKZGYwPWRmMFtpcy5maW5pdGUoZGYwJHBzZXVkb3RpbWUpLF0KZGYwPWRmMFtvcmRlcihkZjAkcHNldWRvdGltZSxkZWNyZWFzaW5nID0gRiksLGRyb3A9Rl0KZGYwJHg9ZGYwJHBzZXVkb3RpbWUvbWF4KGRmMCRwc2V1ZG90aW1lKQpkZl9wc2V1ZG90aW1lX2xpc3QkbW5uX2Rlbm9pc2VkX2FsbD1kZjAKYGBgCgotIEZlYXR1cmUgcGxvdHMgb2YgYEZDR1IzQWAgYW5kIGBTMTAwQThgCgpgYGB7cn0KcD1nZXRfcGxvdDQoZGYwMCA9IGRmMCkKYGBgCgpgYGB7ciwgZmlnLmhlaWdodD00LGZpZy53aWR0aD0xOH0KcApgYGAKCmBgYHtyfQpkZl9kZW49Y29sRGF0YShjZHMpCnR0MT1rcy50ZXN0KGRmX2RlbiRQc2V1ZG90aW1lW2RmX2RlbiRkYXRhc2V0X2JhdGNoPT0iVDEiXSxkZl9kZW4kUHNldWRvdGltZVtkZl9kZW4kZGF0YXNldF9iYXRjaD09IlQzIl0pCnR0MQp0dDI9a3MudGVzdChkZl9kZW4kUHNldWRvdGltZVtkZl9kZW4kZGF0YXNldF9iYXRjaD09IlQxIl0sZGZfZGVuJFBzZXVkb3RpbWVbZGZfZGVuJGRhdGFzZXRfYmF0Y2g9PSJUMiJdKQp0dDIKdHQzPWtzLnRlc3QoZGZfZGVuJFBzZXVkb3RpbWVbZGZfZGVuJGRhdGFzZXRfYmF0Y2g9PSJUMiJdLGRmX2RlbiRQc2V1ZG90aW1lW2RmX2RlbiRkYXRhc2V0X2JhdGNoPT0iVDMiXSkKdHQzCmBgYAoKYGBge3J9ClN0YWJsZTVbMTMsMjo0XT1tYXRyaXgoZ2V0X3BfbmV3KGModHQxJHAudmFsdWUsdHQyJHAudmFsdWUsdHQzJHAudmFsdWUpLGModHQxJHN0YXRpc3RpYyx0dDIkc3RhdGlzdGljLHR0MyRzdGF0aXN0aWMpKSwxLDMpCmBgYAoKCgoKIyBNb25vY2xlMyB1c2luZyBzY2Fub3JhbWEKCgpgYGB7cn0KYWRhdGE9YWQkcmVhZF9oNWFkKCIuLi9maW5hbF9wcm9jZXNzZWRfcmVzdWx0cy9zY2Fub3JhbWEgUmVzdWx0cy9hZGF0YV9BTEwuaDVhZCIpIwpgYGAKCmBgYHtyfQpjZWxsLm1ldGEuZGF0YT1weV90b19yKGFkYXRhJG9icykKY2VsbC5tZXRhLmRhdGEkZGF0YXNldF9iYXRjaD1wbHlyOjptYXB2YWx1ZXMoY2VsbC5tZXRhLmRhdGEkYmF0Y2hfbGFiZWwsbmFtZXMobWFwcnVsZXMpLG1hcHJ1bGVzKQpnZW5lX2FubjA9cHlfdG9fcihhZGF0YSRyYXckdmFyKQpnZW5lX2Fubj1kYXRhLmZyYW1lKGdlbmVfc2hvcnRfbmFtZSA9IG1ha2UudW5pcXVlKHJvd25hbWVzKGdlbmVfYW5uMCkpLAogICAgICAgICAgICAgICAgICAgIHJvdy5uYW1lcyA9IG1ha2UudW5pcXVlKHJvd25hbWVzKGdlbmVfYW5uMCkpKQptdHg9dChweV90b19yKGFkYXRhJFgkdG9jc2MoKSkpI2FkYXRhJHJhdwpjb2xuYW1lcyhtdHgpPWNlbGwubWV0YS5kYXRhJGNlbGxuYW1lCnJvd25hbWVzKG10eCk9cm93bmFtZXMoZ2VuZV9hbm4pCm10eF9zaXplZmFjdG9yPTFlNC9jb2xTdW1zKG10eCkKYGBgCgojIyBVc2luZyBsYXRlbnQKCmBgYHtyfQojbXR4PW10eFtnZW5lX2FubiRWYXJpYW5jZVR5cGU9PSJIVkciLF0KY2RzIDwtIG5ld19jZWxsX2RhdGFfc2V0KG10eCwgY2VsbF9tZXRhZGF0YSA9IGNlbGwubWV0YS5kYXRhLGdlbmVfbWV0YWRhdGEgPWdlbmVfYW5uKQojIyBTdGVwIDE6IE5vcm1hbGl6ZSBhbmQgcHJlLXByb2Nlc3MgdGhlIGRhdGEKY2RzIDwtIHByZXByb2Nlc3NfY2RzKGNkcywgbnVtX2RpbSA9IDUwLG1ldGhvZD0iUENBIixub3JtX21ldGhvZD0ibG9nIikKCnRtcDA9cHlfdG9fcihhZGF0YSRvYnNtWyJYX3NjYW5vcmFtYSJdKQpjb2xuYW1lcyh0bXAwKT1wYXN0ZTAoIlBDIiwxOm5jb2wodG1wMCkpCnJlZHVjZWREaW1zKGNkcykkUENBPXRtcDAKCiMjIFN0ZXAgMjogUmVtb3ZlIGJhdGNoIGVmZmVjdHMgd2l0aCBjZWxsIGFsaWdubWVudAojI2NkcyA8LSBhbGlnbl9jZHMoY2RzLCBhbGlnbm1lbnRfZ3JvdXAgPSAiQmF0Y2hJRCIsIHJlc2lkdWFsX21vZGVsX2Zvcm11bGFfc3RyID0gTlVMTCkKIyMgU3RlcCAzOiBSZWR1Y2UgdGhlIGRpbWVuc2lvbnMgdXNpbmcgVU1BUApjZHMgPC0gcmVkdWNlX2RpbWVuc2lvbihjZHMscmVkdWN0aW9uX21ldGhvZCA9ICJVTUFQIixwcmVwcm9jZXNzX21ldGhvZD0iUENBIikKCiMjIFN0ZXAgNDogQ2x1c3RlciB0aGUgY2VsbHMKY2RzIDwtIGNsdXN0ZXJfY2VsbHMoY2RzLHJlZHVjdGlvbl9tZXRob2QgPSJVTUFQIixjbHVzdGVyX21ldGhvZCA9ICJsZWlkZW4iKQoKIyBDb25zdHJ1Y3QgdGhlIGdyYXBoCiMgTm90ZSB0aGF0LCBmb3IgdGhlIHJlc3Qgb2YgdGhlIGNvZGUgdG8gcnVuLCB0aGUgZ3JhcGggc2hvdWxkIGJlIGZ1bGx5IChwYXJ0aW9ubHkpIGNvbm5lY3RlZAojIyBTdGVwIDU6IExlYXJuIGEgZ3JhcGgKY2RzIDwtIGxlYXJuX2dyYXBoKGNkcywgdXNlX3BhcnRpdGlvbiA9IFQsdmVyYm9zZSA9IEYpCmNvbERhdGEoY2RzKSRjbHVzdGVycz1jZHNAY2x1c3RlcnMkVU1BUCRjbHVzdGVycwpwMT1wbG90X2NlbGxzKGNkcyxjb2xvcl9jZWxsc19ieSA9ICJwYXJ0aXRpb24iLGxhYmVsX2NlbGxfZ3JvdXBzID0gRikrdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIpCnAyPXBsb3RfY2VsbHMoY2RzLGNvbG9yX2NlbGxzX2J5ID0gImNsdXN0ZXJzIixsYWJlbF9jZWxsX2dyb3Vwcz1GLGdyYXBoX2xhYmVsX3NpemU9MiwgbGFiZWxfbGVhdmVzPUYsbGFiZWxfYnJhbmNoX3BvaW50cz1GKSt0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIikKcD1jb3dwbG90OjpwbG90X2dyaWQocDEscDIsYWxpZ24gPSAiaCIsbmNvbCA9IDMpCmBgYAoKYGBge3IsIGZpZy5oZWlnaHQ9NSxmaWcud2lkdGg9MTh9CnAKYGBgCgpgYGB7cn0KIyMgU3RlcCA2OiBPcmRlciBjZWxscwojIHJvb3QgY2VsbHMKaWRzPWdldF9lYXJsaWVzdF9wcmluY2lwYWxfbm9kZShjZHMsY2x1c3Rlcj1jKCIyIikpI25lZWQgdG8gc3BlY2lmeQpjZHMgPC0gb3JkZXJfY2VsbHMoY2RzLCByb290X3ByX25vZGVzPWlkcykKI3Bsb3RfY2VsbHMoY2RzLGNvbG9yX2NlbGxzX2J5ID0gInBzZXVkb3RpbWUiKQpgYGAKCmBgYHtyLGZpZy5oZWlnaHQ9NSxmaWcud2lkdGg9MTh9CmNvbERhdGEoY2RzKSRwc2V1ZG90aW1lPXBzZXVkb3RpbWUoY2RzKQpjb2xEYXRhKGNkcykkUHNldWRvdGltZT1jb2xEYXRhKGNkcykkcHNldWRvdGltZS9tYXgoY29sRGF0YShjZHMpJHBzZXVkb3RpbWUsbmEucm0gPSBUKQojc2F2ZVJEUyhjZHMsZmlsZT0iY2RzX3NjYW5vcmFtYS5yZHMiKQpkZl9kZW49cERhdGEoY2RzKVssYygiUHNldWRvdGltZSIsImRhdGFzZXRfYmF0Y2giKV0KZGZfZGVuPWFzLmRhdGEuZnJhbWUoZGZfZGVuWyFpcy5pbmZpbml0ZShkZl9kZW4kUHNldWRvdGltZSksXSkKc2V0LnNlZWQoMTApCgp0aGVtZV91c2U9dGhlbWUobGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT0xNiksCiAgICAgICAgICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT0yMCkpCgpwX21vbm9jbGVfc2Nhbm9yYW1hX2xhdGVudF9odmdfMT1wbG90X2NlbGxzKGNkcyxjb2xvcl9jZWxsc19ieSA9ICJkYXRhc2V0X2JhdGNoIiwsZ3JhcGhfbGFiZWxfc2l6ZT0wLGFscGhhPTEsY2VsbF9zaXplID0gMC42KSsKICBndWlkZXMoY29sb3VyID0gZ3VpZGVfbGVnZW5kKG92ZXJyaWRlLmFlcyA9IGxpc3QoYWxwaGE9MC43LCBzaXplPTUpKSkrCiAgdGhlbWVfdXNlKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiKQogICAgICAgICAgCnBfbW9ub2NsZV9zY2Fub3JhbWFfbGF0ZW50X2h2Z18yPXBsb3RfY2VsbHMoY2RzLGNvbG9yX2NlbGxzX2J5ID0gIlBzZXVkb3RpbWUiLGxhYmVsX2JyYW5jaF9wb2ludHM9VCxncmFwaF9sYWJlbF9zaXplPTIsYWxwaGE9MSxjZWxsX3NpemUgPSAwLjYpKwogICAgICAgICAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIiwKICAgICAgICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQodmp1c3QgPSAwLjIpLAogICAgICAgICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KGFuZ2xlPS01MCApLAogICAgICAgICAgICAgICAgICBsZWdlbmQua2V5LmhlaWdodCA9IHVuaXQoMC41LCJjbSIpLAogICAgICAgICAgICAgICAgICBsZWdlbmQua2V5LndpZHRoID0gdW5pdCgxLCJjbSIpKSsKICAgICAgICAgICAgZ3VpZGVzKGNvbG9yID0gZ3VpZGVfY29sb3VyYmFyKGxhYmVsLnBvc2l0aW9uID0gInRvcCIpKSt0aGVtZV91c2UKCnBfbW9ub2NsZV9zY2Fub3JhbWFfbGF0ZW50X2h2Z18zPWdncGxvdChkYXRhPWRmX2RlbikrZ2VvbV9kZW5zaXR5KGFlcyh4PVBzZXVkb3RpbWUsZmlsbD1kYXRhc2V0X2JhdGNoKSxhbHBoYT0wLjcpKwogICAgICAgICAgICBzY2FsZV95X2NvbnRpbnVvdXMoZXhwYW5kID0gYygwLDApKSsKICAgICAgICAgICAgc2NhbGVfeF9jb250aW51b3VzKGV4cGFuZCA9IGMoMCwwKSkrCiAgICAgICAgICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0idG9wIikrdGhlbWVfdXNlCgpwX21vbm9jbGVfc2Nhbm9yYW1hX2xhdGVudF9odmc9ZWdnOjpnZ2FycmFuZ2UocF9tb25vY2xlX3NjYW5vcmFtYV9sYXRlbnRfaHZnXzEscF9tb25vY2xlX3NjYW5vcmFtYV9sYXRlbnRfaHZnXzIscF9tb25vY2xlX3NjYW5vcmFtYV9sYXRlbnRfaHZnXzMsbmNvbD0zLGRyYXc9RikKYGBgCgpgYGB7ciwgZmlnLmhlaWdodD01LGZpZy53aWR0aD0xOH0KcF9tb25vY2xlX3NjYW5vcmFtYV9sYXRlbnRfaHZnCmBgYAoKCmBgYHtyfQojY2RzX2V4cHJzPUZldGNoRGF0YShvYmowLHZhcnMgPSBjKCJGQ0dSM0EiLCJTMTAwQTgiKSkKI2RmMD1kYXRhLmZyYW1lKGNiaW5kKHBzZXVkb3RpbWU9cERhdGEoY2RzKSRQc2V1ZG90aW1lLGNkc19leHBycykpCmNkc19leHBycz1hcy5tYXRyaXgoU2luZ2xlQ2VsbEV4cGVyaW1lbnQ6OmNvdW50cyhjZHMpW2MoIkZDR1IzQSIsIlMxMDBBOCIpLF0pCmRmMD1kYXRhLmZyYW1lKGNiaW5kKHBzZXVkb3RpbWU9cERhdGEoY2RzKSRQc2V1ZG90aW1lLHQoY2RzX2V4cHJzKSkpCmRmMCRVTUFQXzE9cmVkdWNlZERpbXMoY2RzKSRVTUFQWywxXQpkZjAkVU1BUF8yPXJlZHVjZWREaW1zKGNkcykkVU1BUFssMl0KZGYwJEJhdGNoSUQ9cERhdGEoY2RzKSRkYXRhc2V0X2JhdGNoCmRmMD1kZjBbaXMuZmluaXRlKGRmMCRwc2V1ZG90aW1lKSxdCmRmMD1kZjBbb3JkZXIoZGYwJHBzZXVkb3RpbWUsZGVjcmVhc2luZyA9IEYpLCxkcm9wPUZdCmRmMCR4PWRmMCRwc2V1ZG90aW1lL21heChkZjAkcHNldWRvdGltZSkKZGZfcHNldWRvdGltZV9saXN0JHNjYW5vcmFtYV9sYXRlbnRfaHZnPWRmMApgYGAKCi0gRmVhdHVyZSBwbG90cyBvZiBgRkNHUjNBYCBhbmQgYFMxMDBBOGAKCmBgYHtyfQpwPWdldF9wbG90NChkZjAwID0gZGYwKQpgYGAKCmBgYHtyLCBmaWcuaGVpZ2h0PTQsZmlnLndpZHRoPTE4fQpwCmBgYAoKCgpgYGB7cn0KZGZfZGVuPWNvbERhdGEoY2RzKQp0dDE9a3MudGVzdChkZl9kZW4kUHNldWRvdGltZVtkZl9kZW4kZGF0YXNldF9iYXRjaD09IlQxIl0sZGZfZGVuJFBzZXVkb3RpbWVbZGZfZGVuJGRhdGFzZXRfYmF0Y2g9PSJUMyJdKQp0dDEKdHQyPWtzLnRlc3QoZGZfZGVuJFBzZXVkb3RpbWVbZGZfZGVuJGRhdGFzZXRfYmF0Y2g9PSJUMSJdLGRmX2RlbiRQc2V1ZG90aW1lW2RmX2RlbiRkYXRhc2V0X2JhdGNoPT0iVDIiXSkKdHQyCnR0Mz1rcy50ZXN0KGRmX2RlbiRQc2V1ZG90aW1lW2RmX2RlbiRkYXRhc2V0X2JhdGNoPT0iVDIiXSxkZl9kZW4kUHNldWRvdGltZVtkZl9kZW4kZGF0YXNldF9iYXRjaD09IlQzIl0pCnR0MwpgYGAKCmBgYHtyfQpTdGFibGU1WzE0LDI6NF09bWF0cml4KGdldF9wX25ldyhjKHR0MSRwLnZhbHVlLHR0MiRwLnZhbHVlLHR0MyRwLnZhbHVlKSxjKHR0MSRzdGF0aXN0aWMsdHQyJHN0YXRpc3RpYyx0dDMkc3RhdGlzdGljKSksMSwzKQpgYGAKCgojIyBIVkdzIGRlbm9pc2VkCgpgYGB7cn0KI2NkcyA8LSBuZXdfY2VsbF9kYXRhX3NldChtdHhbcm93bmFtZXMobXR4KSVpbiVodmdfZ2VuZXMkZ2VuZW5hbWUsXSwgY2VsbF9tZXRhZGF0YSA9IGNlbGwubWV0YS5kYXRhLGdlbmVfbWV0YWRhdGEgPWdlbmVfYW5uW2dlbmVfYW5uJGdlbmVfc2hvcnRfbmFtZSVpbiVodmdfZ2VuZXMkZ2VuZW5hbWUsLGRyb3A9Rl0pCmNkcyA8LSBuZXdfY2VsbF9kYXRhX3NldChtdHgsIGNlbGxfbWV0YWRhdGEgPSBjZWxsLm1ldGEuZGF0YSxnZW5lX21ldGFkYXRhID1nZW5lX2FubikKIyMgU3RlcCAxOiBOb3JtYWxpemUgYW5kIHByZS1wcm9jZXNzIHRoZSBkYXRhCmNkcyA8LSBwcmVwcm9jZXNzX2NkcyhjZHMsIG51bV9kaW0gPSA1MCxtZXRob2Q9IlBDQSIsbm9ybV9tZXRob2Q9ImxvZyIsdmVyYm9zZSA9IEYpCgp0bXAwPXB5X3RvX3IoYWRhdGEkb2JzbVsiWF9odmdwY2EiXSkKY29sbmFtZXModG1wMCk9cGFzdGUwKCJQQyIsMTpuY29sKHRtcDApKQpyZWR1Y2VkRGltcyhjZHMpJFBDQT10bXAwCgojIyBTdGVwIDI6IFJlbW92ZSBiYXRjaCBlZmZlY3RzIHdpdGggY2VsbCBhbGlnbm1lbnQKIyNjZHMgPC0gYWxpZ25fY2RzKGNkcywgYWxpZ25tZW50X2dyb3VwID0gIkJhdGNoSUQiLCByZXNpZHVhbF9tb2RlbF9mb3JtdWxhX3N0ciA9IE5VTEwpCiMjIFN0ZXAgMzogUmVkdWNlIHRoZSBkaW1lbnNpb25zIHVzaW5nIFVNQVAKY2RzIDwtIHJlZHVjZV9kaW1lbnNpb24oY2RzLHJlZHVjdGlvbl9tZXRob2QgPSAiVU1BUCIscHJlcHJvY2Vzc19tZXRob2Q9IlBDQSIsdmVyYm9zZSA9IEYpCgojIyBTdGVwIDQ6IENsdXN0ZXIgdGhlIGNlbGxzCmNkcyA8LSBjbHVzdGVyX2NlbGxzKGNkcyxyZWR1Y3Rpb25fbWV0aG9kID0iVU1BUCIsY2x1c3Rlcl9tZXRob2QgPSAibGVpZGVuIix2ZXJib3NlID0gRikKCiMgQ29uc3RydWN0IHRoZSBncmFwaAojIE5vdGUgdGhhdCwgZm9yIHRoZSByZXN0IG9mIHRoZSBjb2RlIHRvIHJ1biwgdGhlIGdyYXBoIHNob3VsZCBiZSBmdWxseSAocGFydGlvbmx5KSBjb25uZWN0ZWQKIyMgU3RlcCA1OiBMZWFybiBhIGdyYXBoCmNkcyA8LSBsZWFybl9ncmFwaChjZHMsIHVzZV9wYXJ0aXRpb24gPSBULHZlcmJvc2UgPSBGKQpjb2xEYXRhKGNkcykkY2x1c3RlcnM9Y2RzQGNsdXN0ZXJzJFVNQVAkY2x1c3RlcnMKcDE9cGxvdF9jZWxscyhjZHMsY29sb3JfY2VsbHNfYnkgPSAicGFydGl0aW9uIixsYWJlbF9jZWxsX2dyb3VwcyA9IEYpK3RoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiKQpwMj1wbG90X2NlbGxzKGNkcyxjb2xvcl9jZWxsc19ieSA9ICJjbHVzdGVycyIsbGFiZWxfY2VsbF9ncm91cHM9RixncmFwaF9sYWJlbF9zaXplPTIsIGxhYmVsX2xlYXZlcz1GLGxhYmVsX2JyYW5jaF9wb2ludHM9RikrdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIpCnA9Y293cGxvdDo6cGxvdF9ncmlkKHAxLHAyLGFsaWduID0gImgiLG5jb2wgPSAzKQpgYGAKCmBgYHtyLCBmaWcuaGVpZ2h0PTUsZmlnLndpZHRoPTE4fQpwCmBgYAoKYGBge3J9CiMjIFN0ZXAgNjogT3JkZXIgY2VsbHMKIyByb290IGNlbGxzCmlkcz1nZXRfZWFybGllc3RfcHJpbmNpcGFsX25vZGUoY2RzLGNsdXN0ZXI9YygiMiIpKQpjZHMgPC0gb3JkZXJfY2VsbHMoY2RzLCByb290X3ByX25vZGVzPWlkcykKI3Bsb3RfY2VsbHMoY2RzLGNvbG9yX2NlbGxzX2J5ID0gInBzZXVkb3RpbWUiKQpgYGAKCgpgYGB7cixmaWcuaGVpZ2h0PTUsZmlnLndpZHRoPTE4fQpjb2xEYXRhKGNkcykkcHNldWRvdGltZT1wc2V1ZG90aW1lKGNkcykKY29sRGF0YShjZHMpJFBzZXVkb3RpbWU9Y29sRGF0YShjZHMpJHBzZXVkb3RpbWUvbWF4KGNvbERhdGEoY2RzKSRwc2V1ZG90aW1lLG5hLnJtID0gVCkKZGZfZGVuPXBEYXRhKGNkcylbLGMoIlBzZXVkb3RpbWUiLCJkYXRhc2V0X2JhdGNoIildCmRmX2Rlbj1hcy5kYXRhLmZyYW1lKGRmX2RlblshaXMuaW5maW5pdGUoZGZfZGVuJFBzZXVkb3RpbWUpLF0pCnNldC5zZWVkKDEwKQoKdGhlbWVfdXNlPXRoZW1lKGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9MTYpLAogICAgICAgICAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9MjApKQoKcF9tb25vY2xlX3NjYW5vcmFtYV9kZW5vaXNlZF9odmdfMT1wbG90X2NlbGxzKGNkcyxjb2xvcl9jZWxsc19ieSA9ICJkYXRhc2V0X2JhdGNoIiwsZ3JhcGhfbGFiZWxfc2l6ZT0wLGFscGhhPTEsY2VsbF9zaXplID0gMC42KSsKICBndWlkZXMoY29sb3VyID0gZ3VpZGVfbGVnZW5kKG92ZXJyaWRlLmFlcyA9IGxpc3QoYWxwaGE9MC43LCBzaXplPTUpKSkrCiAgdGhlbWVfdXNlKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiKQogICAgICAgICAgCnBfbW9ub2NsZV9zY2Fub3JhbWFfZGVub2lzZWRfaHZnXzI9cGxvdF9jZWxscyhjZHMsY29sb3JfY2VsbHNfYnkgPSAiUHNldWRvdGltZSIsbGFiZWxfYnJhbmNoX3BvaW50cz1ULGdyYXBoX2xhYmVsX3NpemU9MixhbHBoYT0xLGNlbGxfc2l6ZSA9IDAuNikrCiAgICAgICAgICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiLAogICAgICAgICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dCh2anVzdCA9IDAuMiksCiAgICAgICAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoYW5nbGU9LTUwICksCiAgICAgICAgICAgICAgICAgIGxlZ2VuZC5rZXkuaGVpZ2h0ID0gdW5pdCgwLjUsImNtIiksCiAgICAgICAgICAgICAgICAgIGxlZ2VuZC5rZXkud2lkdGggPSB1bml0KDEsImNtIikpKwogICAgICAgICAgICBndWlkZXMoY29sb3IgPSBndWlkZV9jb2xvdXJiYXIobGFiZWwucG9zaXRpb24gPSAidG9wIikpK3RoZW1lX3VzZQoKcF9tb25vY2xlX3NjYW5vcmFtYV9kZW5vaXNlZF9odmdfMz1nZ3Bsb3QoZGF0YT1kZl9kZW4pK2dlb21fZGVuc2l0eShhZXMoeD1Qc2V1ZG90aW1lLGZpbGw9ZGF0YXNldF9iYXRjaCksYWxwaGE9MC43KSsKICAgICAgICAgICAgc2NhbGVfeV9jb250aW51b3VzKGV4cGFuZCA9IGMoMCwwKSkrCiAgICAgICAgICAgIHNjYWxlX3hfY29udGludW91cyhleHBhbmQgPSBjKDAsMCkpKwogICAgICAgICAgICB0aGVtZShsZWdlbmQucG9zaXRpb249InRvcCIpK3RoZW1lX3VzZQoKcF9tb25vY2xlX3NjYW5vcmFtYV9kZW5vaXNlZF9odmc9ZWdnOjpnZ2FycmFuZ2UocF9tb25vY2xlX3NjYW5vcmFtYV9kZW5vaXNlZF9odmdfMSxwX21vbm9jbGVfc2Nhbm9yYW1hX2Rlbm9pc2VkX2h2Z18yLHBfbW9ub2NsZV9zY2Fub3JhbWFfZGVub2lzZWRfaHZnXzMsbmNvbD0zLGRyYXc9RikKYGBgCgpgYGB7ciwgZmlnLmhlaWdodD01LGZpZy53aWR0aD0xOH0KcF9tb25vY2xlX3NjYW5vcmFtYV9kZW5vaXNlZF9odmcKYGBgCgpgYGB7cn0KI2Nkc19leHBycz1GZXRjaERhdGEob2JqMCx2YXJzID0gYygiRkNHUjNBIiwiUzEwMEE4IikpCiNkZjA9ZGF0YS5mcmFtZShjYmluZChwc2V1ZG90aW1lPXBEYXRhKGNkcykkUHNldWRvdGltZSxjZHNfZXhwcnMpKQpjZHNfZXhwcnM9YXMubWF0cml4KFNpbmdsZUNlbGxFeHBlcmltZW50Ojpjb3VudHMoY2RzKVtjKCJGQ0dSM0EiLCJTMTAwQTgiKSxdKQpkZjA9ZGF0YS5mcmFtZShjYmluZChwc2V1ZG90aW1lPXBEYXRhKGNkcykkUHNldWRvdGltZSx0KGNkc19leHBycykqbXR4X3NpemVmYWN0b3IpKQpkZjAkVU1BUF8xPXJlZHVjZWREaW1zKGNkcykkVU1BUFssMV0KZGYwJFVNQVBfMj1yZWR1Y2VkRGltcyhjZHMpJFVNQVBbLDJdCmRmMCRCYXRjaElEPXBEYXRhKGNkcykkZGF0YXNldF9iYXRjaApkZjA9ZGYwW2lzLmZpbml0ZShkZjAkcHNldWRvdGltZSksXQpkZjA9ZGYwW29yZGVyKGRmMCRwc2V1ZG90aW1lLGRlY3JlYXNpbmcgPSBGKSwsZHJvcD1GXQpkZjAkeD1kZjAkcHNldWRvdGltZS9tYXgoZGYwJHBzZXVkb3RpbWUpCmRmX3BzZXVkb3RpbWVfbGlzdCRzY2Fub3JhbWFfZGVub2lzZWRfaHZnPWRmMApgYGAKCi0gRmVhdHVyZSBwbG90cyBvZiBgRkNHUjNBYCBhbmQgYFMxMDBBOGAKCmBgYHtyfQpwPWdldF9wbG90NChkZjAwID0gZGYwKQpgYGAKCmBgYHtyLCBmaWcuaGVpZ2h0PTQsZmlnLndpZHRoPTE4fQpwCmBgYAoKYGBge3J9CmRmX2Rlbj1jb2xEYXRhKGNkcykKdHQxPWtzLnRlc3QoZGZfZGVuJFBzZXVkb3RpbWVbZGZfZGVuJGRhdGFzZXRfYmF0Y2g9PSJUMSJdLGRmX2RlbiRQc2V1ZG90aW1lW2RmX2RlbiRkYXRhc2V0X2JhdGNoPT0iVDMiXSkKdHQxCnR0Mj1rcy50ZXN0KGRmX2RlbiRQc2V1ZG90aW1lW2RmX2RlbiRkYXRhc2V0X2JhdGNoPT0iVDEiXSxkZl9kZW4kUHNldWRvdGltZVtkZl9kZW4kZGF0YXNldF9iYXRjaD09IlQyIl0pCnR0Mgp0dDM9a3MudGVzdChkZl9kZW4kUHNldWRvdGltZVtkZl9kZW4kZGF0YXNldF9iYXRjaD09IlQyIl0sZGZfZGVuJFBzZXVkb3RpbWVbZGZfZGVuJGRhdGFzZXRfYmF0Y2g9PSJUMyJdKQp0dDMKYGBgCgpgYGB7cn0KU3RhYmxlNVsxNSwyOjRdPW1hdHJpeChnZXRfcF9uZXcoYyh0dDEkcC52YWx1ZSx0dDIkcC52YWx1ZSx0dDMkcC52YWx1ZSksYyh0dDEkc3RhdGlzdGljLHR0MiRzdGF0aXN0aWMsdHQzJHN0YXRpc3RpYykpLDEsMykKYGBgCgoKIyMgQWxsIGdlbmVzIGRlbm9pc2VkCgpgYGB7cn0KI2NkcyA8LSBuZXdfY2VsbF9kYXRhX3NldChtdHhbcm93bmFtZXMobXR4KSVpbiVodmdfZ2VuZXMkZ2VuZW5hbWUsXSwgY2VsbF9tZXRhZGF0YSA9IGNlbGwubWV0YS5kYXRhLGdlbmVfbWV0YWRhdGEgPWdlbmVfYW5uW2dlbmVfYW5uJGdlbmVfc2hvcnRfbmFtZSVpbiVodmdfZ2VuZXMkZ2VuZW5hbWUsLGRyb3A9Rl0pCmNkcyA8LSBuZXdfY2VsbF9kYXRhX3NldChtdHgsIGNlbGxfbWV0YWRhdGEgPSBjZWxsLm1ldGEuZGF0YSxnZW5lX21ldGFkYXRhID1nZW5lX2FubikKIyMgU3RlcCAxOiBOb3JtYWxpemUgYW5kIHByZS1wcm9jZXNzIHRoZSBkYXRhCmNkcyA8LSBwcmVwcm9jZXNzX2NkcyhjZHMsIG51bV9kaW0gPSAzMCxtZXRob2Q9IlBDQSIsbm9ybV9tZXRob2Q9ImxvZyIsdmVyYm9zZSA9IEYpCgp0bXAwPXB5X3RvX3IoYWRhdGEkb2JzbVsiWF9wY2EiXSkKY29sbmFtZXModG1wMCk9cGFzdGUwKCJQQyIsMTpuY29sKHRtcDApKQpyZWR1Y2VkRGltcyhjZHMpJFBDQT10bXAwWywxOjMwXQoKIyMgU3RlcCAyOiBSZW1vdmUgYmF0Y2ggZWZmZWN0cyB3aXRoIGNlbGwgYWxpZ25tZW50CiMjY2RzIDwtIGFsaWduX2NkcyhjZHMsIGFsaWdubWVudF9ncm91cCA9ICJCYXRjaElEIiwgcmVzaWR1YWxfbW9kZWxfZm9ybXVsYV9zdHIgPSBOVUxMKQojIyBTdGVwIDM6IFJlZHVjZSB0aGUgZGltZW5zaW9ucyB1c2luZyBVTUFQCmNkcyA8LSByZWR1Y2VfZGltZW5zaW9uKGNkcyxyZWR1Y3Rpb25fbWV0aG9kID0gIlVNQVAiLHByZXByb2Nlc3NfbWV0aG9kPSJQQ0EiLHZlcmJvc2UgPSBGKQoKIyMgU3RlcCA0OiBDbHVzdGVyIHRoZSBjZWxscwpjZHMgPC0gY2x1c3Rlcl9jZWxscyhjZHMscmVkdWN0aW9uX21ldGhvZCA9IlVNQVAiLGNsdXN0ZXJfbWV0aG9kID0gImxlaWRlbiIsdmVyYm9zZSA9IEYpCgojIENvbnN0cnVjdCB0aGUgZ3JhcGgKIyBOb3RlIHRoYXQsIGZvciB0aGUgcmVzdCBvZiB0aGUgY29kZSB0byBydW4sIHRoZSBncmFwaCBzaG91bGQgYmUgZnVsbHkgKHBhcnRpb25seSkgY29ubmVjdGVkCiMjIFN0ZXAgNTogTGVhcm4gYSBncmFwaApjZHMgPC0gbGVhcm5fZ3JhcGgoY2RzLCB1c2VfcGFydGl0aW9uID0gVCx2ZXJib3NlID0gRikKY29sRGF0YShjZHMpJGNsdXN0ZXJzPWNkc0BjbHVzdGVycyRVTUFQJGNsdXN0ZXJzCnAxPXBsb3RfY2VsbHMoY2RzLGNvbG9yX2NlbGxzX2J5ID0gInBhcnRpdGlvbiIsbGFiZWxfY2VsbF9ncm91cHMgPSBGKSt0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIikKcDI9cGxvdF9jZWxscyhjZHMsY29sb3JfY2VsbHNfYnkgPSAiY2x1c3RlcnMiLGxhYmVsX2NlbGxfZ3JvdXBzPUYsZ3JhcGhfbGFiZWxfc2l6ZT0yLCBsYWJlbF9sZWF2ZXM9RixsYWJlbF9icmFuY2hfcG9pbnRzPUYpK3RoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiKQpwPWNvd3Bsb3Q6OnBsb3RfZ3JpZChwMSxwMixhbGlnbiA9ICJoIixuY29sID0gMykKYGBgCgpgYGB7ciwgZmlnLmhlaWdodD01LGZpZy53aWR0aD0xOH0KcApgYGAKCmBgYHtyfQojIyBTdGVwIDY6IE9yZGVyIGNlbGxzCiMgcm9vdCBjZWxscwppZHM9Z2V0X2VhcmxpZXN0X3ByaW5jaXBhbF9ub2RlKGNkcyxjbHVzdGVyPWMoIjEiKSkKY2RzIDwtIG9yZGVyX2NlbGxzKGNkcywgcm9vdF9wcl9ub2Rlcz1pZHMpCiNwbG90X2NlbGxzKGNkcyxjb2xvcl9jZWxsc19ieSA9ICJwc2V1ZG90aW1lIikKYGBgCgoKYGBge3IsZmlnLmhlaWdodD01LGZpZy53aWR0aD0xOH0KY29sRGF0YShjZHMpJHBzZXVkb3RpbWU9cHNldWRvdGltZShjZHMpCmNvbERhdGEoY2RzKSRQc2V1ZG90aW1lPWNvbERhdGEoY2RzKSRwc2V1ZG90aW1lL21heChjb2xEYXRhKGNkcykkcHNldWRvdGltZSxuYS5ybSA9IFQpCmRmX2Rlbj1wRGF0YShjZHMpWyxjKCJQc2V1ZG90aW1lIiwiZGF0YXNldF9iYXRjaCIpXQpkZl9kZW49YXMuZGF0YS5mcmFtZShkZl9kZW5bIWlzLmluZmluaXRlKGRmX2RlbiRQc2V1ZG90aW1lKSxdKQpzZXQuc2VlZCgxMCkKCnRoZW1lX3VzZT10aGVtZShsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTE2KSwKICAgICAgICAgICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTIwKSkKCnBfbW9ub2NsZV9zY2Fub3JhbWFfZGVub2lzZWRfYWxsXzE9cGxvdF9jZWxscyhjZHMsY29sb3JfY2VsbHNfYnkgPSAiZGF0YXNldF9iYXRjaCIsLGdyYXBoX2xhYmVsX3NpemU9MCxhbHBoYT0xLGNlbGxfc2l6ZSA9IDAuNikrCiAgZ3VpZGVzKGNvbG91ciA9IGd1aWRlX2xlZ2VuZChvdmVycmlkZS5hZXMgPSBsaXN0KGFscGhhPTAuNywgc2l6ZT01KSkpKwogIHRoZW1lX3VzZSsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIikKICAgICAgICAgIApwX21vbm9jbGVfc2Nhbm9yYW1hX2Rlbm9pc2VkX2FsbF8yPXBsb3RfY2VsbHMoY2RzLGNvbG9yX2NlbGxzX2J5ID0gIlBzZXVkb3RpbWUiLGxhYmVsX2JyYW5jaF9wb2ludHM9VCxncmFwaF9sYWJlbF9zaXplPTIsYWxwaGE9MSxjZWxsX3NpemUgPSAwLjYpKwogICAgICAgICAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIiwKICAgICAgICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQodmp1c3QgPSAwLjIpLAogICAgICAgICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KGFuZ2xlPS01MCApLAogICAgICAgICAgICAgICAgICBsZWdlbmQua2V5LmhlaWdodCA9IHVuaXQoMC41LCJjbSIpLAogICAgICAgICAgICAgICAgICBsZWdlbmQua2V5LndpZHRoID0gdW5pdCgxLCJjbSIpKSsKICAgICAgICAgICAgZ3VpZGVzKGNvbG9yID0gZ3VpZGVfY29sb3VyYmFyKGxhYmVsLnBvc2l0aW9uID0gInRvcCIpKSt0aGVtZV91c2UKCnBfbW9ub2NsZV9zY2Fub3JhbWFfZGVub2lzZWRfYWxsXzM9Z2dwbG90KGRhdGE9ZGZfZGVuKStnZW9tX2RlbnNpdHkoYWVzKHg9UHNldWRvdGltZSxmaWxsPWRhdGFzZXRfYmF0Y2gpLGFscGhhPTAuNykrCiAgICAgICAgICAgIHNjYWxlX3lfY29udGludW91cyhleHBhbmQgPSBjKDAsMCkpKwogICAgICAgICAgICBzY2FsZV94X2NvbnRpbnVvdXMoZXhwYW5kID0gYygwLDApKSsKICAgICAgICAgICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJ0b3AiKSt0aGVtZV91c2UKCnBfbW9ub2NsZV9zY2Fub3JhbWFfZGVub2lzZWRfYWxsPWVnZzo6Z2dhcnJhbmdlKHBfbW9ub2NsZV9zY2Fub3JhbWFfZGVub2lzZWRfYWxsXzEscF9tb25vY2xlX3NjYW5vcmFtYV9kZW5vaXNlZF9hbGxfMixwX21vbm9jbGVfc2Nhbm9yYW1hX2Rlbm9pc2VkX2FsbF8zLG5jb2w9MyxkcmF3PUYpCmBgYAoKYGBge3IsIGZpZy5oZWlnaHQ9NSxmaWcud2lkdGg9MTh9CnBfbW9ub2NsZV9zY2Fub3JhbWFfZGVub2lzZWRfYWxsCmBgYAoKYGBge3J9CiNjZHNfZXhwcnM9RmV0Y2hEYXRhKG9iajAsdmFycyA9IGMoIkZDR1IzQSIsIlMxMDBBOCIpKQojZGYwPWRhdGEuZnJhbWUoY2JpbmQocHNldWRvdGltZT1wRGF0YShjZHMpJFBzZXVkb3RpbWUsY2RzX2V4cHJzKSkKY2RzX2V4cHJzPWFzLm1hdHJpeChTaW5nbGVDZWxsRXhwZXJpbWVudDo6Y291bnRzKGNkcylbYygiRkNHUjNBIiwiUzEwMEE4IiksXSkKZGYwPWRhdGEuZnJhbWUoY2JpbmQocHNldWRvdGltZT1wRGF0YShjZHMpJFBzZXVkb3RpbWUsdChjZHNfZXhwcnMpKm10eF9zaXplZmFjdG9yKSkKZGYwJFVNQVBfMT1yZWR1Y2VkRGltcyhjZHMpJFVNQVBbLDFdCmRmMCRVTUFQXzI9cmVkdWNlZERpbXMoY2RzKSRVTUFQWywyXQpkZjAkQmF0Y2hJRD1wRGF0YShjZHMpJGRhdGFzZXRfYmF0Y2gKZGYwPWRmMFtpcy5maW5pdGUoZGYwJHBzZXVkb3RpbWUpLF0KZGYwPWRmMFtvcmRlcihkZjAkcHNldWRvdGltZSxkZWNyZWFzaW5nID0gRiksLGRyb3A9Rl0KZGYwJHg9ZGYwJHBzZXVkb3RpbWUvbWF4KGRmMCRwc2V1ZG90aW1lKQpkZl9wc2V1ZG90aW1lX2xpc3Qkc2Nhbm9yYW1hX2Rlbm9pc2VkX2FsbD1kZjAKYGBgCgotIEZlYXR1cmUgcGxvdHMgb2YgYEZDR1IzQWAgYW5kIGBTMTAwQThgCgpgYGB7cn0KcD1nZXRfcGxvdDQoZGYwMCA9IGRmMCkKYGBgCgpgYGB7ciwgZmlnLmhlaWdodD00LGZpZy53aWR0aD0xOH0KcApgYGAKCmBgYHtyfQpkZl9kZW49Y29sRGF0YShjZHMpCnR0MT1rcy50ZXN0KGRmX2RlbiRQc2V1ZG90aW1lW2RmX2RlbiRkYXRhc2V0X2JhdGNoPT0iVDEiXSxkZl9kZW4kUHNldWRvdGltZVtkZl9kZW4kZGF0YXNldF9iYXRjaD09IlQzIl0pCnR0MQp0dDI9a3MudGVzdChkZl9kZW4kUHNldWRvdGltZVtkZl9kZW4kZGF0YXNldF9iYXRjaD09IlQxIl0sZGZfZGVuJFBzZXVkb3RpbWVbZGZfZGVuJGRhdGFzZXRfYmF0Y2g9PSJUMiJdKQp0dDIKdHQzPWtzLnRlc3QoZGZfZGVuJFBzZXVkb3RpbWVbZGZfZGVuJGRhdGFzZXRfYmF0Y2g9PSJUMiJdLGRmX2RlbiRQc2V1ZG90aW1lW2RmX2RlbiRkYXRhc2V0X2JhdGNoPT0iVDMiXSkKdHQzCmBgYAoKYGBge3J9ClN0YWJsZTVbMTYsMjo0XT1tYXRyaXgoZ2V0X3BfbmV3KGModHQxJHAudmFsdWUsdHQyJHAudmFsdWUsdHQzJHAudmFsdWUpLGModHQxJHN0YXRpc3RpYyx0dDIkc3RhdGlzdGljLHR0MyRzdGF0aXN0aWMpKSwxLDMpCmBgYAoKYGBge3J9CnN1cHByZXNzUGFja2FnZVN0YXJ0dXBNZXNzYWdlcyhsaWJyYXJ5KGNvd3Bsb3QpKQpgYGAKCmBgYHtyfQojU3VwcGxlbWVudGFyeSBUYWJsZSA1CndyaXRlLnRhYmxlKFN0YWJsZTUsZmlsZT0iS1NfdGFibGUuY3N2IixzZXA9IiwiKQpvcGVueGxzeDo6d3JpdGUueGxzeChTdGFibGU1LGZpbGU9IktTX3RhYmxlLnhsc3giKQoKU3RhYmxlNSAlPiUKICBrYWJsZSgpICU+JQogIGthYmxlX3N0eWxpbmcoKQpgYGAKCiMgRmlndXJlcwoKIyMgIE1haW4gRmlndXJlIChGaWd1cmUgNSkKCmBgYHtyLCBmaWcud2lkdGg9MzAsZmlnLmhlaWdodD0yNX0KZmlnX3dpZHRoPTMwCmZpZ19oZWlnaHQ9MjUKbGFiZWxzPWxldHRlcnNbMTo1XQpNZXRob2RzPWMoIlJhdyBjb3VudCBIVkdzIiwiUmF3IGNvdW50IEFsbCIsIkNhckRFQyAobGF0ZW50KSIsIkNhckRFQyAoZGVub2lzZWQgSFZHcykiLCJDYXJERUMgKGRlbm9pc2VkIEFsbCkiLCJzY1ZJIChsYXRlbnQpIiwic2NWSSAoZGVub2lzZWQgSFZHcykiLCJzY1ZJIChkZW5vaXNlZCBBbGwpIiwiRENBIChsYXRlbnQpIiwiRENBIChkZW5vaXNlZCBIVkdzKSIsIkRDQSAoZGVub2lzZWQgQWxsKSIsIk1OTiAoZGVub2lzZWQgSFZHcykiLCJNTk4gKGRlbm9pc2VkIEFsbCkiLCJTY2Fub3JhbWEgKGxhdGVudCkiLCJTY2Fub3JhbWEgKGRlbm9pc2VkIEhWR3MpIiwiU2Nhbm9yYW1hIChkZW5vaXNlZCBBbGwpIikKdXNlX2lkPWMoNCwxNSwxMCw3LDEyKQoKZ2V0X2RyYXdfcGxvdD1mdW5jdGlvbihwbG90X2lkPTEscGxpc3QwKXsKICB4PTAuMDIKICB5PTEtcGxvdF9pZC81CiAgd2lkdGg9MC45OAogIGhlaWdodD0xLzUtMC4wMSAjIHRvdGFsIG51bWJlciBvZiBmaWd1cmVzIGlzIDEyCiAgcHA9ZHJhd19wbG90KGVnZzo6Z2dhcnJhbmdlKHBsb3RzPXBsaXN0MCxucm93ID0gMSxkcmF3ID0gRixuZXdwYWdlID0gRikseCA9IHgseSA9IHksd2lkdGggPSB3aWR0aCxoZWlnaHQgPSBoZWlnaHQpCiAgI2RyYXdfbGFiZWwobGFiZWxzW3Bsb3RfaWRdLHg9eCx5PXkrMS82LGhqdXN0ID0xLHZqdXN0ID0gMC41LHNpemUgPSAzNSkKICByZXR1cm4ocHApCn0KCmdldF9sYWJlbF9wb3M9ZnVuY3Rpb24ocGxvdF9pZD0xKXsKICB4PTAKICB5PTEtcGxvdF9pZC81CiAgI2RyYXdfbGFiZWwobGFiZWxzW3Bsb3RfaWRdLHg9eCx5PXkrMS82LGhqdXN0ID0xLHZqdXN0ID0gMC41LHNpemUgPSAzNSkKICByZXR1cm4oYyh4LHkrMS81LTEvMzApKQp9CgpnZXRfdGl0bGVfcG9zPWZ1bmN0aW9uKHBsb3RfaWQ9MSl7CiAgeD0wLjAxNQogIHk9MS1wbG90X2lkLzUKICAjZHJhd19sYWJlbChsYWJlbHNbcGxvdF9pZF0seD14LHk9eSsxLzYsaGp1c3QgPTEsdmp1c3QgPSAwLjUsc2l6ZSA9IDM1KQogIHJldHVybihjKHgseSsxLzEwLTEvNjApKQp9CgpnZXRfcGxvdF9saXN0PWZ1bmN0aW9uKHgseSl7CiAgeDA9cmVwKGxpc3QoKSxsZW5ndGg9bGVuZ3RoKHgpK2xlbmd0aCh5KSkKICB4MFsxOmxlbmd0aCh4KV09eFsxOjNdCiAgeDBbKGxlbmd0aCh4KSsxKTpsZW5ndGgoeDApXT15WzE6Ml0KICByZXR1cm4oeDApCn0KcD1nZ2RyYXcoKStnZXRfZHJhd19wbG90KDEsZ2V0X3Bsb3RfbGlzdChsaXN0KHBfY2FyREVDX2Rlbm9pc2VkX2h2Z18xK3NjYWxlX2NvbG9yX2JyZXdlcihuYW1lPSJkYXRhc2V0X2JhdGNoIixwYWxldHRlID0gIlNldDIiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBfY2FyREVDX2Rlbm9pc2VkX2h2Z18yLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcF9jYXJERUNfZGVub2lzZWRfaHZnXzMrc2NhbGVfZmlsbF9icmV3ZXIobmFtZT0iZGF0YXNldF9iYXRjaCIscGFsZXR0ZSA9ICJTZXQyIikpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdldF9wbG90NF9zZXAoZGZfcHNldWRvdGltZV9saXN0W1s0XV0pW2MoMyw0KV0pKSsKZ2V0X2RyYXdfcGxvdCgyLGdldF9wbG90X2xpc3QobGlzdChwX21vbm9jbGVfc2Nhbm9yYW1hX2Rlbm9pc2VkX2h2Z18xK3NjYWxlX2NvbG9yX2JyZXdlcihuYW1lPSJkYXRhc2V0X2JhdGNoIixwYWxldHRlID0gIlNldDIiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwX21vbm9jbGVfc2Nhbm9yYW1hX2Rlbm9pc2VkX2h2Z18yLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBfbW9ub2NsZV9zY2Fub3JhbWFfZGVub2lzZWRfaHZnXzMrc2NhbGVfZmlsbF9icmV3ZXIobmFtZT0iZGF0YXNldF9iYXRjaCIscGFsZXR0ZSA9ICJTZXQyIikpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZXRfcGxvdDRfc2VwKGRmX3BzZXVkb3RpbWVfbGlzdFtbMTVdXSlbYygzLDQpXSkpKwogIGdldF9kcmF3X3Bsb3QoMyxnZXRfcGxvdF9saXN0KGxpc3QocF9kY2FfZGVub2lzZWRfaHZnXzErc2NhbGVfY29sb3JfYnJld2VyKG5hbWU9ImRhdGFzZXRfYmF0Y2giLHBhbGV0dGUgPSAiU2V0MiIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcF9kY2FfZGVub2lzZWRfaHZnXzIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwX2RjYV9kZW5vaXNlZF9odmdfMytzY2FsZV9maWxsX2JyZXdlcihuYW1lPSJkYXRhc2V0X2JhdGNoIixwYWxldHRlID0gIlNldDIiKSksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdldF9wbG90NF9zZXAoZGZfcHNldWRvdGltZV9saXN0W1sxMF1dKVtjKDMsNCldKSkrCiAgZ2V0X2RyYXdfcGxvdCg0LGdldF9wbG90X2xpc3QobGlzdChwX3NjdmlfZGVub2lzZWRfaHZnXzErc2NhbGVfY29sb3JfYnJld2VyKG5hbWU9ImRhdGFzZXRfYmF0Y2giLHBhbGV0dGUgPSAiU2V0MiIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcF9zY3ZpX2Rlbm9pc2VkX2h2Z18yLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcF9zY3ZpX2Rlbm9pc2VkX2h2Z18zK3NjYWxlX2ZpbGxfYnJld2VyKG5hbWU9ImRhdGFzZXRfYmF0Y2giLHBhbGV0dGUgPSAiU2V0MiIpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZXRfcGxvdDRfc2VwKGRmX3BzZXVkb3RpbWVfbGlzdFtbN11dKVtjKDMsNCldKSkrCmdldF9kcmF3X3Bsb3QoNSxnZXRfcGxvdF9saXN0KGxpc3QocF9tbm5fZGVub2lzZWRfaHZnXzErc2NhbGVfY29sb3JfYnJld2VyKG5hbWU9ImRhdGFzZXRfYmF0Y2giLHBhbGV0dGUgPSAiU2V0MiIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBfbW5uX2Rlbm9pc2VkX2h2Z18yLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBfbW5uX2Rlbm9pc2VkX2h2Z18zK3NjYWxlX2ZpbGxfYnJld2VyKG5hbWU9ImRhdGFzZXRfYmF0Y2giLHBhbGV0dGUgPSAiU2V0MiIpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2V0X3Bsb3Q0X3NlcChkZl9wc2V1ZG90aW1lX2xpc3RbWzEyXV0pW2MoMyw0KV0pKQoKZm9yIChpIGluIDE6bGVuZ3RoKHVzZV9pZCkpewogIHA9cCtkcmF3X2xhYmVsKGxhYmVsc1tpXSx4PWdldF9sYWJlbF9wb3MoaSlbMV0seT1nZXRfbGFiZWxfcG9zKGkpWzJdLHNpemU9MzAsY29sb3I9ImJsYWNrIixoanVzdCA9IDAsdmp1c3QgPSAxKSsKICAgIGRyYXdfbGFiZWwocGFzdGUwKE1ldGhvZHNbdXNlX2lkW2ldXSxjb2xsYXBzZSA9ICIiKSwKICAgICAgICAgICAgICAgeD1nZXRfdGl0bGVfcG9zKGkpWzFdLAogICAgICAgICAgICAgICB5PWdldF90aXRsZV9wb3MoaSlbMl0sCiAgICAgICAgICAgICAgIHNpemU9MjAsCiAgICAgICAgICAgICAgIGNvbG9yID0gImJsYWNrIixhbmdsZSA9IDkwLGhqdXN0ID0gMC41LHZqdXN0ID0gMC41KQp9CmBgYAoKYGBge3IsIGZpZy53aWR0aD0zMCxmaWcuaGVpZ2h0PTI1fQpwCmBgYAoKYGBge3J9Cmdnc2F2ZShwLGZpbGVuYW1lID0gIi4vcmV2aXNlZF9maWd1cmVzL0NhckRFQ19tb25vY3l0ZV9NYWluX2ZpZzEucGRmIix3aWR0aCA9IDMwLGhlaWdodCA9IDI1KQpnZ3NhdmUocCxmaWxlbmFtZSA9ICIuL3JldmlzZWRfZmlndXJlcy9DYXJERUNfbW9ub2N5dGVfTWFpbl9maWcxLnRpZmYiLHdpZHRoID0gMzAsaGVpZ2h0ID0gMjUsY29tcHJlc3Npb249Imx6dyIpCmBgYAoKCiMjICBTdXBwbGVtZW50YXJ5IEZpZ3VyZXMgYWJvdXQgbW9ub2N5dGUKCjEuIFJhdyAKCmBgYHtyfQpwbGlzdDA9cmVwKGxpc3QoKSxsZW5ndGg9OSkKcGxpc3QwWzE6M109bGlzdChwX29yaV9hbGxfMStzY2FsZV9jb2xvcl9icmV3ZXIobmFtZT0iZGF0YXNldF9iYXRjaCIscGFsZXR0ZSA9ICJTZXQyIikrdGhlbWVfdXNlLAogICAgICAgICAgICAgICAgIHBfb3JpX2FsbF8yLAogICAgICAgICAgICAgICAgIHBfb3JpX2FsbF8zK3NjYWxlX2ZpbGxfYnJld2VyKG5hbWU9ImRhdGFzZXRfYmF0Y2giLHBhbGV0dGUgPSAiU2V0MiIpK3RoZW1lKHBsb3QubWFyZ2luID0gdW5pdChjKDAsMCwxLDApLCJjbSIpKSlbMTozXQpwbGlzdDBbNDo1XT1nZXRfcGxvdDRfc2VwKGRmX3BzZXVkb3RpbWVfbGlzdFtbMl1dKVsxOjJdCnBsaXN0MFtbNl1dPWdncGxvdCgpK3RoZW1lX3ZvaWQoKSt0aGVtZShwbG90Lm1hcmdpbiA9IHVuaXQoYygwLDAsMSwwKSwiY20iKSkKcGxpc3QwWzc6OF09Z2V0X3Bsb3Q0X3NlcChkZl9wc2V1ZG90aW1lX2xpc3RbWzJdXSlbMzo0XQpwbGlzdDBbWzldXT1nZ3Bsb3QoKSt0aGVtZV92b2lkKCkKcD1nZ2RyYXcoKStkcmF3X3Bsb3QoZWdnOjpnZ2FycmFuZ2UocGxvdHMgPSBwbGlzdDAsbmNvbD0zLGRyYXcgPSBGKSx4PTAseT0wLHdpZHRoPTEsaGVpZ2h0PTEpKwogZHJhd19sYWJlbCgiYSIseD0wLHk9MS0wLjAyLHNpemU9MzAsY29sb3I9ImJsYWNrIixoanVzdCA9IDAsdmp1c3QgPSAxKSsKIGRyYXdfbGFiZWwoImIiLHg9MCx5PTIvMy0wLjAzLHNpemU9MzAsY29sb3I9ImJsYWNrIixoanVzdCA9IDAsdmp1c3QgPSAxKSsKICAgZHJhd19sYWJlbCgiYyIseD0wLHk9MS8zLTAuMDMsc2l6ZT0zMCxjb2xvcj0iYmxhY2siLGhqdXN0ID0gMCx2anVzdCA9IDEpCmBgYAoKYGBge3IsIGZpZy53aWR0aD0xOCxmaWcuaGVpZ2h0PTE2fQpwCmBgYAoKYGBge3J9Cmdnc2F2ZShwLGZpbGVuYW1lID0gIi4vcmV2aXNlZF9maWd1cmVzL0NhckRFQ19tb25vY3l0ZV9TdXBwX2ZpZzEucGRmIix3aWR0aCA9IDE4LGhlaWdodCA9IDE2KQpnZ3NhdmUocCxmaWxlbmFtZSA9ICIuL3JldmlzZWRfZmlndXJlcy9DYXJERUNfbW9ub2N5dGVfU3VwcF9maWcxLnRpZmYiLHdpZHRoID0gMTgsaGVpZ2h0ID0gMTYsY29tcHJlc3Npb249Imx6dyIpCmBgYAoKMi4gQWxsIGdlbmVzCgpgYGB7cixmaWcud2lkdGg9MzYsZmlnLmhlaWdodD0zMH0KZmlnX3dpZHRoPTMwCmZpZ19oZWlnaHQ9MjUKbGFiZWxzPWxldHRlcnNbMTo1XQpNZXRob2RzPWMoIlJhdyBjb3VudCBIVkdzIiwiUmF3IGNvdW50IEFsbCIsIkNhckRFQyAobGF0ZW50KSIsIkNhckRFQyAoZGVub2lzZWQgSFZHcykiLCJDYXJERUMgKGRlbm9pc2VkIEFsbCkiLCJzY1ZJIChsYXRlbnQpIiwic2NWSSAoZGVub2lzZWQgSFZHcykiLCJzY1ZJIChkZW5vaXNlZCBBbGwpIiwiRENBIChsYXRlbnQpIiwiRENBIChkZW5vaXNlZCBIVkdzKSIsIkRDQSAoZGVub2lzZWQgQWxsKSIsIk1OTiAoZGVub2lzZWQgSFZHcykiLCJNTk4gKGRlbm9pc2VkIEFsbCkiLCJTY2Fub3JhbWEgKGxhdGVudCkiLCJTY2Fub3JhbWEgKGRlbm9pc2VkIEhWR3MpIiwiU2Nhbm9yYW1hIChkZW5vaXNlZCBBbGwpIikKdXNlX2lkPWMoNSwxNiwxMSw4LDEzKQoKZ2V0X2RyYXdfcGxvdD1mdW5jdGlvbihwbG90X2lkPTEscGxpc3QwKXsKICB4PTAuMDIKICB5PTEtcGxvdF9pZC81CiAgd2lkdGg9MC45OAogIGhlaWdodD0xLzUtMC4wMSAjIHRvdGFsIG51bWJlciBvZiBmaWd1cmVzIGlzIDEyCiAgcHA9ZHJhd19wbG90KGVnZzo6Z2dhcnJhbmdlKHBsb3RzPXBsaXN0MCxucm93ID0gMSxkcmF3ID0gRixuZXdwYWdlID0gRikseCA9IHgseSA9IHksd2lkdGggPSB3aWR0aCxoZWlnaHQgPSBoZWlnaHQpCiAgI2RyYXdfbGFiZWwobGFiZWxzW3Bsb3RfaWRdLHg9eCx5PXkrMS82LGhqdXN0ID0xLHZqdXN0ID0gMC41LHNpemUgPSAzNSkKICByZXR1cm4ocHApCn0KCmdldF9sYWJlbF9wb3M9ZnVuY3Rpb24ocGxvdF9pZD0xKXsKICB4PTAKICB5PTEtcGxvdF9pZC81CiAgI2RyYXdfbGFiZWwobGFiZWxzW3Bsb3RfaWRdLHg9eCx5PXkrMS82LGhqdXN0ID0xLHZqdXN0ID0gMC41LHNpemUgPSAzNSkKICByZXR1cm4oYyh4LHkrMS81LTEvMzApKQp9CgpnZXRfdGl0bGVfcG9zPWZ1bmN0aW9uKHBsb3RfaWQ9MSl7CiAgeD0wLjAxNQogIHk9MS1wbG90X2lkLzUKICAjZHJhd19sYWJlbChsYWJlbHNbcGxvdF9pZF0seD14LHk9eSsxLzYsaGp1c3QgPTEsdmp1c3QgPSAwLjUsc2l6ZSA9IDM1KQogIHJldHVybihjKHgseSsxLzEwLTEvNjApKQp9CmdldF9wbG90X2xpc3Q9ZnVuY3Rpb24oeCx5KXsKICB4MD1yZXAobGlzdCgpLGxlbmd0aD1sZW5ndGgoeCkrbGVuZ3RoKHkpKQogIHgwWzE6bGVuZ3RoKHgpXT14WzE6M10KICB4MFsobGVuZ3RoKHgpKzEpOmxlbmd0aCh4MCldPXlbMToyXQogIHJldHVybih4MCkKfQoKcD1nZ2RyYXcoKSsKICBnZXRfZHJhd19wbG90KDEsZ2V0X3Bsb3RfbGlzdChsaXN0KHBfY2FyREVDX2Rlbm9pc2VkX2FsbF8xK3NjYWxlX2NvbG9yX2JyZXdlcihuYW1lPSJkYXRhc2V0X2JhdGNoIixwYWxldHRlID0gIlNldDIiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBfY2FyREVDX2Rlbm9pc2VkX2FsbF8yLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcF9jYXJERUNfZGVub2lzZWRfYWxsXzMrc2NhbGVfZmlsbF9icmV3ZXIobmFtZT0iZGF0YXNldF9iYXRjaCIscGFsZXR0ZSA9ICJTZXQyIikpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZXRfcGxvdDRfc2VwKGRmX3BzZXVkb3RpbWVfbGlzdFtbNV1dKVtjKDMsNCldKSkrCiBnZXRfZHJhd19wbG90KDIsZ2V0X3Bsb3RfbGlzdChsaXN0KHBfbW9ub2NsZV9zY2Fub3JhbWFfZGVub2lzZWRfYWxsXzErc2NhbGVfY29sb3JfYnJld2VyKG5hbWU9ImRhdGFzZXRfYmF0Y2giLHBhbGV0dGUgPSAiU2V0MiIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBfbW9ub2NsZV9zY2Fub3JhbWFfZGVub2lzZWRfYWxsXzIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcF9tb25vY2xlX3NjYW5vcmFtYV9kZW5vaXNlZF9hbGxfMytzY2FsZV9maWxsX2JyZXdlcihuYW1lPSJkYXRhc2V0X2JhdGNoIixwYWxldHRlID0gIlNldDIiKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdldF9wbG90NF9zZXAoZGZfcHNldWRvdGltZV9saXN0W1sxNl1dKVtjKDMsNCldKSkrCiAgZ2V0X2RyYXdfcGxvdCgzLGdldF9wbG90X2xpc3QobGlzdChwX2RjYV9kZW5vaXNlZF9hbGxfMStzY2FsZV9jb2xvcl9icmV3ZXIobmFtZT0iZGF0YXNldF9iYXRjaCIscGFsZXR0ZSA9ICJTZXQyIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwX2RjYV9kZW5vaXNlZF9hbGxfMiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBfZGNhX2Rlbm9pc2VkX2FsbF8zK3NjYWxlX2ZpbGxfYnJld2VyKG5hbWU9ImRhdGFzZXRfYmF0Y2giLHBhbGV0dGUgPSAiU2V0MiIpKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2V0X3Bsb3Q0X3NlcChkZl9wc2V1ZG90aW1lX2xpc3RbWzExXV0pW2MoMyw0KV0pKSsKICBnZXRfZHJhd19wbG90KDQsZ2V0X3Bsb3RfbGlzdChsaXN0KHBfc2NWSV9kZW5vaXNlZF9hbGxfMStzY2FsZV9jb2xvcl9icmV3ZXIobmFtZT0iZGF0YXNldF9iYXRjaCIscGFsZXR0ZSA9ICJTZXQyIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwX3NjVklfZGVub2lzZWRfYWxsXzIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwX3NjVklfZGVub2lzZWRfYWxsXzMrc2NhbGVfZmlsbF9icmV3ZXIobmFtZT0iZGF0YXNldF9iYXRjaCIscGFsZXR0ZSA9ICJTZXQyIikpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZXRfcGxvdDRfc2VwKGRmX3BzZXVkb3RpbWVfbGlzdFtbOF1dKVtjKDMsNCldKSkrCiAgZ2V0X2RyYXdfcGxvdCg1LGdldF9wbG90X2xpc3QobGlzdChwX21ubl9kZW5vaXNlZF9hbGxfMStzY2FsZV9jb2xvcl9icmV3ZXIobmFtZT0iZGF0YXNldF9iYXRjaCIscGFsZXR0ZSA9ICJTZXQyIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwX21ubl9kZW5vaXNlZF9hbGxfMiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBfbW5uX2Rlbm9pc2VkX2FsbF8zK3NjYWxlX2ZpbGxfYnJld2VyKG5hbWU9ImRhdGFzZXRfYmF0Y2giLHBhbGV0dGUgPSAiU2V0MiIpKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2V0X3Bsb3Q0X3NlcChkZl9wc2V1ZG90aW1lX2xpc3RbWzEzXV0pW2MoMyw0KV0pKQogCmZvciAoaSBpbiAxOmxlbmd0aCh1c2VfaWQpKXsKICBwPXArZHJhd19sYWJlbChsYWJlbHNbaV0seD1nZXRfbGFiZWxfcG9zKGkpWzFdLHk9Z2V0X2xhYmVsX3BvcyhpKVsyXSxzaXplPTMwLGNvbG9yPSJibGFjayIsaGp1c3QgPSAwLHZqdXN0ID0gMSkrCiAgICBkcmF3X2xhYmVsKHBhc3RlMChNZXRob2RzW3VzZV9pZFtpXV0sY29sbGFwc2UgPSAiIiksCiAgICAgICAgICAgICAgIHg9Z2V0X3RpdGxlX3BvcyhpKVsxXSwKICAgICAgICAgICAgICAgeT1nZXRfdGl0bGVfcG9zKGkpWzJdLAogICAgICAgICAgICAgICBzaXplPTIwLAogICAgICAgICAgICAgICBjb2xvciA9ICJibGFjayIsYW5nbGUgPSA5MCxoanVzdCA9IDAuNSx2anVzdCA9IDAuNSkKfQpgYGAKCmBgYHtyLCBmaWcud2lkdGg9MzAsZmlnLmhlaWdodD0yNX0KcApgYGAKCmBgYHtyfQpnZ3NhdmUocCxmaWxlbmFtZSA9ICIuL3JldmlzZWRfZmlndXJlcy9DYXJERUNfbW9ub2N5dGVfU3VwcF9maWcyLnBkZiIsd2lkdGggPSAzMCxoZWlnaHQgPSAyNSxsaW1pdHNpemUgPSBGKQpnZ3NhdmUocCxmaWxlbmFtZSA9ICIuL3JldmlzZWRfZmlndXJlcy9DYXJERUNfbW9ub2N5dGVfU3VwcF9maWcyLnRpZmYiLHdpZHRoID0gMzAsaGVpZ2h0ID0gMjUsbGltaXRzaXplID0gRixjb21wcmVzc2lvbj0ibHp3IikKYGBgCgoKMy4gTGF0ZW50CgpgYGB7cixmaWcud2lkdGg9MzYsZmlnLmhlaWdodD0zMH0KZmlnX3dpZHRoPTMwCmZpZ19oZWlnaHQ9MjUKbGFiZWxzPWxldHRlcnNbMTo1XQpNZXRob2RzPWMoIlJhdyBjb3VudCBIVkdzIiwiUmF3IGNvdW50IEFsbCIsIkNhckRFQyAobGF0ZW50KSIsIkNhckRFQyAoZGVub2lzZWQgSFZHcykiLCJDYXJERUMgKGRlbm9pc2VkIEFsbCkiLCJzY1ZJIChsYXRlbnQpIiwic2NWSSAoZGVub2lzZWQgSFZHcykiLCJzY1ZJIChkZW5vaXNlZCBBbGwpIiwiRENBIChsYXRlbnQpIiwiRENBIChkZW5vaXNlZCBIVkdzKSIsIkRDQSAoZGVub2lzZWQgQWxsKSIsIk1OTiAoZGVub2lzZWQgSFZHcykiLCJNTk4gKGRlbm9pc2VkIEFsbCkiLCJTY2Fub3JhbWEgKGxhdGVudCkiLCJTY2Fub3JhbWEgKGRlbm9pc2VkIEhWR3MpIiwiU2Nhbm9yYW1hIChkZW5vaXNlZCBBbGwpIikKCnVzZV9pZD1jKDMsMTQsOSw2LDEpCgpnZXRfZHJhd19wbG90PWZ1bmN0aW9uKHBsb3RfaWQ9MSxwbGlzdDApewogIHg9MC4wMgogIHk9MS1wbG90X2lkLzUKICB3aWR0aD0wLjk4CiAgaGVpZ2h0PTEvNS0wLjAxICMgdG90YWwgbnVtYmVyIG9mIGZpZ3VyZXMgaXMgMTIKICBwcD1kcmF3X3Bsb3QoZWdnOjpnZ2FycmFuZ2UocGxvdHM9cGxpc3QwLG5yb3cgPSAxLGRyYXcgPSBGLG5ld3BhZ2UgPSBGKSx4ID0geCx5ID0geSx3aWR0aCA9IHdpZHRoLGhlaWdodCA9IGhlaWdodCkKICAjZHJhd19sYWJlbChsYWJlbHNbcGxvdF9pZF0seD14LHk9eSsxLzYsaGp1c3QgPTEsdmp1c3QgPSAwLjUsc2l6ZSA9IDM1KQogIHJldHVybihwcCkKfQoKZ2V0X2xhYmVsX3Bvcz1mdW5jdGlvbihwbG90X2lkPTEpewogIHg9MAogIHk9MS1wbG90X2lkLzUKICAjZHJhd19sYWJlbChsYWJlbHNbcGxvdF9pZF0seD14LHk9eSsxLzYsaGp1c3QgPTEsdmp1c3QgPSAwLjUsc2l6ZSA9IDM1KQogIHJldHVybihjKHgseSsxLzUtMS8zMCkpCn0KCmdldF90aXRsZV9wb3M9ZnVuY3Rpb24ocGxvdF9pZD0xKXsKICB4PTAuMDE1CiAgeT0xLXBsb3RfaWQvNQogICNkcmF3X2xhYmVsKGxhYmVsc1twbG90X2lkXSx4PXgseT15KzEvNixoanVzdCA9MSx2anVzdCA9IDAuNSxzaXplID0gMzUpCiAgcmV0dXJuKGMoeCx5KzEvMTAtMS82MCkpCn0KZ2V0X3Bsb3RfbGlzdD1mdW5jdGlvbih4LHkpewogIHgwPXJlcChsaXN0KCksbGVuZ3RoPWxlbmd0aCh4KStsZW5ndGgoeSkpCiAgeDBbMTpsZW5ndGgoeCldPXhbMTozXQogIHgwWyhsZW5ndGgoeCkrMSk6bGVuZ3RoKHgwKV09eVsxOjJdCiAgcmV0dXJuKHgwKQp9CgoKcD1nZ2RyYXcoKStnZXRfZHJhd19wbG90KDEsZ2V0X3Bsb3RfbGlzdChsaXN0KHBfY2FyREVDX2xhdGVudF8xK3NjYWxlX2NvbG9yX2JyZXdlcihuYW1lPSJkYXRhc2V0X2JhdGNoIixwYWxldHRlID0gIlNldDIiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBfY2FyREVDX2xhdGVudF8yLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcF9jYXJERUNfbGF0ZW50XzMrc2NhbGVfZmlsbF9icmV3ZXIobmFtZT0iZGF0YXNldF9iYXRjaCIscGFsZXR0ZSA9ICJTZXQyIikpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdldF9wbG90NF9zZXAoZGZfcHNldWRvdGltZV9saXN0W1szXV0pW2MoMyw0KV0pKSsKICBnZXRfZHJhd19wbG90KDIsZ2V0X3Bsb3RfbGlzdChsaXN0KHBfbW9ub2NsZV9zY2Fub3JhbWFfbGF0ZW50X2h2Z18xK3NjYWxlX2NvbG9yX2JyZXdlcihuYW1lPSJkYXRhc2V0X2JhdGNoIixwYWxldHRlID0gIlNldDIiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwX21vbm9jbGVfc2Nhbm9yYW1hX2xhdGVudF9odmdfMiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwX21vbm9jbGVfc2Nhbm9yYW1hX2xhdGVudF9odmdfMytzY2FsZV9maWxsX2JyZXdlcihuYW1lPSJkYXRhc2V0X2JhdGNoIixwYWxldHRlID0gIlNldDIiKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdldF9wbG90NF9zZXAoZGZfcHNldWRvdGltZV9saXN0W1sxNF1dKVtjKDMsNCldKSkrCiAgZ2V0X2RyYXdfcGxvdCgzLGdldF9wbG90X2xpc3QobGlzdChwX2RjYV9sYXRlbnRfYWxsXzErc2NhbGVfY29sb3JfYnJld2VyKG5hbWU9ImRhdGFzZXRfYmF0Y2giLHBhbGV0dGUgPSAiU2V0MiIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcF9kY2FfbGF0ZW50X2FsbF8yLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcF9kY2FfbGF0ZW50X2FsbF8zK3NjYWxlX2ZpbGxfYnJld2VyKG5hbWU9ImRhdGFzZXRfYmF0Y2giLHBhbGV0dGUgPSAiU2V0MiIpKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2V0X3Bsb3Q0X3NlcChkZl9wc2V1ZG90aW1lX2xpc3RbWzldXSlbYygzLDQpXSkpKwogIGdldF9kcmF3X3Bsb3QoNCxnZXRfcGxvdF9saXN0KGxpc3QocF9zY1ZJX2xhdGVudF9hbGxfMStzY2FsZV9jb2xvcl9icmV3ZXIobmFtZT0iZGF0YXNldF9iYXRjaCIscGFsZXR0ZSA9ICJTZXQyIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwX3NjVklfbGF0ZW50X2FsbF8yLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcF9zY1ZJX2xhdGVudF9hbGxfMytzY2FsZV9maWxsX2JyZXdlcihuYW1lPSJkYXRhc2V0X2JhdGNoIixwYWxldHRlID0gIlNldDIiKSksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdldF9wbG90NF9zZXAoZGZfcHNldWRvdGltZV9saXN0W1s2XV0pW2MoMyw0KV0pKSsKICBnZXRfZHJhd19wbG90KDUsZ2V0X3Bsb3RfbGlzdChsaXN0KHBfb3JpXzErc2NhbGVfY29sb3JfYnJld2VyKG5hbWU9ImRhdGFzZXRfYmF0Y2giLHBhbGV0dGUgPSAiU2V0MiIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcF9vcmlfMiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBfb3JpXzMrc2NhbGVfZmlsbF9icmV3ZXIobmFtZT0iZGF0YXNldF9iYXRjaCIscGFsZXR0ZSA9ICJTZXQyIikpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZXRfcGxvdDRfc2VwKGRmX3BzZXVkb3RpbWVfbGlzdFtbMV1dKVtjKDMsNCldKSkKZm9yIChpIGluIDE6bGVuZ3RoKHVzZV9pZCkpewogIHA9cCtkcmF3X2xhYmVsKGxhYmVsc1tpXSx4PWdldF9sYWJlbF9wb3MoaSlbMV0seT1nZXRfbGFiZWxfcG9zKGkpWzJdLHNpemU9MzAsY29sb3I9ImJsYWNrIixoanVzdCA9IDAsdmp1c3QgPSAxKSsKICAgIGRyYXdfbGFiZWwocGFzdGUwKE1ldGhvZHNbdXNlX2lkW2ldXSxjb2xsYXBzZSA9ICIiKSwKICAgICAgICAgICAgICAgeD1nZXRfdGl0bGVfcG9zKGkpWzFdLAogICAgICAgICAgICAgICB5PWdldF90aXRsZV9wb3MoaSlbMl0sCiAgICAgICAgICAgICAgIHNpemU9MjAsCiAgICAgICAgICAgICAgIGNvbG9yID0gImJsYWNrIixhbmdsZSA9IDkwLGhqdXN0ID0gMC41LHZqdXN0ID0gMC41KQp9CmBgYAoKYGBge3IsIGZpZy53aWR0aD0zMCxmaWcuaGVpZ2h0PTI1fQpwCmBgYAoKYGBge3J9Cmdnc2F2ZShwLGZpbGVuYW1lID0gIi4vcmV2aXNlZF9maWd1cmVzL0NhckRFQ19tb25vY3l0ZV9TdXBwX2ZpZzMucGRmIix3aWR0aCA9IDMwLGhlaWdodCA9IDI1LGxpbWl0c2l6ZSA9IEYpCmdnc2F2ZShwLGZpbGVuYW1lID0gIi4vcmV2aXNlZF9maWd1cmVzL0NhckRFQ19tb25vY3l0ZV9TdXBwX2ZpZzMudGlmZiIsd2lkdGggPSAzMCxoZWlnaHQgPSAyNSxsaW1pdHNpemUgPSBGLGNvbXByZXNzaW9uPSJsenciKQpgYGAKCiMjIFMxMDBBOCBhbmQgRkNHUjNBJ3MgZmVhdHVyZSBwbG90cwoKMS4gbW9ub2NsZXMnIFVNQVAgb2YgZGVub2lzZWQgY291bnRzIGZyb20gSFZHcyAKCmBgYHtyfQpmaWdfd2lkdGg9MTUKZmlnX2hlaWdodD0yNQpsYWJlbHM9bGV0dGVyc1sxOjEzXQpNZXRob2RzPWMoIlJhdyBjb3VudCBIVkdzIiwiUmF3IGNvdW50IEFsbCIsIkNhckRFQyAobGF0ZW50KSIsIkNhckRFQyAoZGVub2lzZWQgSFZHcykiLCJDYXJERUMgKGRlbm9pc2VkIEFsbCkiLCJzY1ZJIChsYXRlbnQpIiwic2NWSSAoZGVub2lzZWQgSFZHcykiLCJzY1ZJIChkZW5vaXNlZCBBbGwpIiwiRENBIChsYXRlbnQpIiwiRENBIChkZW5vaXNlZCBIVkdzKSIsIkRDQSAoZGVub2lzZWQgQWxsKSIsIk1OTiAoZGVub2lzZWQgSFZHcykiLCJNTk4gKGRlbm9pc2VkIEFsbCkiLCJTY2Fub3JhbWEgKGxhdGVudCkiLCJTY2Fub3JhbWEgKGRlbm9pc2VkIEhWR3MpIiwiU2Nhbm9yYW1hIChkZW5vaXNlZCBBbGwpIikKdXNlX2lkPWMoNCwxNSwxMCw3LDEyKQojdXNlX2lkPWMoMyw5LDYsMSkKZ2V0X2RyYXdfcGxvdD1mdW5jdGlvbihwbG90X2lkPTEscGxpc3QwKXsKICB4PTAuMDIKICB5PTEtcGxvdF9pZC81CiAgd2lkdGg9MC45OAogIGhlaWdodD0xLzUtMC4wMSAjIHRvdGFsIG51bWJlciBvZiBmaWd1cmVzIGlzIDEyCiAgcHA9ZHJhd19wbG90KGVnZzo6Z2dhcnJhbmdlKHBsb3RzPXBsaXN0MCxucm93ID0gMSxkcmF3ID0gRixuZXdwYWdlID0gRikseCA9IHgseSA9IHksd2lkdGggPSB3aWR0aCxoZWlnaHQgPSBoZWlnaHQpCiAgI2RyYXdfbGFiZWwobGFiZWxzW3Bsb3RfaWRdLHg9eCx5PXkrMS82LGhqdXN0ID0xLHZqdXN0ID0gMC41LHNpemUgPSAzNSkKICByZXR1cm4ocHApCn0KCmdldF9sYWJlbF9wb3M9ZnVuY3Rpb24ocGxvdF9pZD0xKXsKICB4PTAKICB5PTEtcGxvdF9pZC81CiAgI2RyYXdfbGFiZWwobGFiZWxzW3Bsb3RfaWRdLHg9eCx5PXkrMS82LGhqdXN0ID0xLHZqdXN0ID0gMC41LHNpemUgPSAzNSkKICByZXR1cm4oYyh4LHkrMS81LTEvMTAwKSkKfQoKZ2V0X3RpdGxlX3Bvcz1mdW5jdGlvbihwbG90X2lkPTEpewogIHg9MC4wMTUKICB5PTEtcGxvdF9pZC81CiAgI2RyYXdfbGFiZWwobGFiZWxzW3Bsb3RfaWRdLHg9eCx5PXkrMS82LGhqdXN0ID0xLHZqdXN0ID0gMC41LHNpemUgPSAzNSkKICByZXR1cm4oYyh4LHkrMS8xMC0xLzEwMCkpCn0KZ2V0X3Bsb3RfbGlzdD1mdW5jdGlvbih4LHkpewogIHgwPXJlcChsaXN0KCksbGVuZ3RoPWxlbmd0aCh4KStsZW5ndGgoeSkpCiAgeDBbMTpsZW5ndGgoeCldPXhbMTozXQogIHgwWyhsZW5ndGgoeCkrMSk6bGVuZ3RoKHgwKV09eVsxOjJdCiAgcmV0dXJuKHgwKQp9CgpwPWdnZHJhdygpCmZvcihpIGluIDE6bGVuZ3RoKHVzZV9pZCkpewogIHA9cCtnZXRfZHJhd19wbG90KGksZ2V0X3Bsb3Q0X3NlcChkZl9wc2V1ZG90aW1lX2xpc3RbW3VzZV9pZFtpXV1dKVtjKDEsMildKQp9Cgpmb3IgKGkgaW4gMTpsZW5ndGgodXNlX2lkKSl7CiAgcD1wK2RyYXdfbGFiZWwobGFiZWxzW2ldLHg9Z2V0X2xhYmVsX3BvcyhpKVsxXSx5PWdldF9sYWJlbF9wb3MoaSlbMl0sc2l6ZT0zMCxjb2xvcj0iYmxhY2siLGhqdXN0ID0gMCx2anVzdCA9IDEpKwogICAgZHJhd19sYWJlbChwYXN0ZTAoTWV0aG9kc1t1c2VfaWRbaV1dLGNvbGxhcHNlID0gIiIpLAogICAgICAgICAgICAgICB4PWdldF90aXRsZV9wb3MoaSlbMV0sCiAgICAgICAgICAgICAgIHk9Z2V0X3RpdGxlX3BvcyhpKVsyXSwKICAgICAgICAgICAgICAgc2l6ZT0yMCwKICAgICAgICAgICAgICAgY29sb3IgPSAiYmxhY2siLGFuZ2xlID0gOTAsaGp1c3QgPSAwLjUsdmp1c3QgPSAwLjUpCn0KCmBgYAoKYGBge3IgZmlnLndpZHRoPTE1LGZpZy5oZWlnaHQ9MjV9Cmdnc2F2ZSgiLi9yZXZpc2VkX2ZpZ3VyZXMvQ2FyREVDX21vbm9jeXRlX1N1cHBfZmlnNC5wZGYiLHAsd2lkdGggPSAxNSxoZWlnaHQgPSAyNSkKZ2dzYXZlKCIuL3JldmlzZWRfZmlndXJlcy9DYXJERUNfbW9ub2N5dGVfU3VwcF9maWc0LnRpZmYiLHAsd2lkdGggPSAxNSxoZWlnaHQgPSAyNSxjb21wcmVzc2lvbj0ibHp3IikKcApgYGAKCjIuIG1vbm9jbGVzJyBVTUFQIG9mIGRlbm9pc2VkIGNvdW50cyBmcm9tIEFsbCBnZW5lcyAKCgpgYGB7cn0KZmlnX3dpZHRoPTE1CmZpZ19oZWlnaHQ9MjUKbGFiZWxzPWxldHRlcnNbMToxM10KTWV0aG9kcz1jKCJSYXcgY291bnQgSFZHcyIsIlJhdyBjb3VudCBBbGwiLCJDYXJERUMgKGxhdGVudCkiLCJDYXJERUMgKGRlbm9pc2VkIEhWR3MpIiwiQ2FyREVDIChkZW5vaXNlZCBBbGwpIiwic2NWSSAobGF0ZW50KSIsInNjVkkgKGRlbm9pc2VkIEhWR3MpIiwic2NWSSAoZGVub2lzZWQgQWxsKSIsIkRDQSAobGF0ZW50KSIsIkRDQSAoZGVub2lzZWQgSFZHcykiLCJEQ0EgKGRlbm9pc2VkIEFsbCkiLCJNTk4gKGRlbm9pc2VkIEhWR3MpIiwiTU5OIChkZW5vaXNlZCBBbGwpIiwiU2Nhbm9yYW1hIChsYXRlbnQpIiwiU2Nhbm9yYW1hIChkZW5vaXNlZCBIVkdzKSIsIlNjYW5vcmFtYSAoZGVub2lzZWQgQWxsKSIpCnVzZV9pZD1jKDUsMTYsMTEsOCwxMykKZ2V0X2RyYXdfcGxvdD1mdW5jdGlvbihwbG90X2lkPTEscGxpc3QwKXsKICB4PTAuMDIKICB5PTEtcGxvdF9pZC81CiAgd2lkdGg9MC45OAogIGhlaWdodD0xLzUtMC4wMSAjIHRvdGFsIG51bWJlciBvZiBmaWd1cmVzIGlzIDEyCiAgcHA9ZHJhd19wbG90KGVnZzo6Z2dhcnJhbmdlKHBsb3RzPXBsaXN0MCxucm93ID0gMSxkcmF3ID0gRixuZXdwYWdlID0gRikseCA9IHgseSA9IHksd2lkdGggPSB3aWR0aCxoZWlnaHQgPSBoZWlnaHQpCiAgI2RyYXdfbGFiZWwobGFiZWxzW3Bsb3RfaWRdLHg9eCx5PXkrMS82LGhqdXN0ID0xLHZqdXN0ID0gMC41LHNpemUgPSAzNSkKICByZXR1cm4ocHApCn0KCmdldF9sYWJlbF9wb3M9ZnVuY3Rpb24ocGxvdF9pZD0xKXsKICB4PTAKICB5PTEtcGxvdF9pZC81CiAgI2RyYXdfbGFiZWwobGFiZWxzW3Bsb3RfaWRdLHg9eCx5PXkrMS82LGhqdXN0ID0xLHZqdXN0ID0gMC41LHNpemUgPSAzNSkKICByZXR1cm4oYyh4LHkrMS81LTEvMTAwKSkKfQoKZ2V0X3RpdGxlX3Bvcz1mdW5jdGlvbihwbG90X2lkPTEpewogIHg9MC4wMTUKICB5PTEtcGxvdF9pZC81CiAgI2RyYXdfbGFiZWwobGFiZWxzW3Bsb3RfaWRdLHg9eCx5PXkrMS82LGhqdXN0ID0xLHZqdXN0ID0gMC41LHNpemUgPSAzNSkKICByZXR1cm4oYyh4LHkrMS8xMC0xLzEwMCkpCn0KZ2V0X3Bsb3RfbGlzdD1mdW5jdGlvbih4LHkpewogIHgwPXJlcChsaXN0KCksbGVuZ3RoPWxlbmd0aCh4KStsZW5ndGgoeSkpCiAgeDBbMTpsZW5ndGgoeCldPXhbMTozXQogIHgwWyhsZW5ndGgoeCkrMSk6bGVuZ3RoKHgwKV09eVsxOjJdCiAgcmV0dXJuKHgwKQp9CgpwPWdnZHJhdygpCmZvcihpIGluIDE6bGVuZ3RoKHVzZV9pZCkpewogIHA9cCtnZXRfZHJhd19wbG90KGksZ2V0X3Bsb3Q0X3NlcChkZl9wc2V1ZG90aW1lX2xpc3RbW3VzZV9pZFtpXV1dKVtjKDEsMildKQp9Cgpmb3IgKGkgaW4gMTpsZW5ndGgodXNlX2lkKSl7CiAgcD1wK2RyYXdfbGFiZWwobGFiZWxzW2ldLHg9Z2V0X2xhYmVsX3BvcyhpKVsxXSx5PWdldF9sYWJlbF9wb3MoaSlbMl0sc2l6ZT0zMCxjb2xvcj0iYmxhY2siLGhqdXN0ID0gMCx2anVzdCA9IDEpKwogICAgZHJhd19sYWJlbChwYXN0ZTAoTWV0aG9kc1t1c2VfaWRbaV1dLGNvbGxhcHNlID0gIiIpLAogICAgICAgICAgICAgICB4PWdldF90aXRsZV9wb3MoaSlbMV0sCiAgICAgICAgICAgICAgIHk9Z2V0X3RpdGxlX3BvcyhpKVsyXSwKICAgICAgICAgICAgICAgc2l6ZT0yMCwKICAgICAgICAgICAgICAgY29sb3IgPSAiYmxhY2siLGFuZ2xlID0gOTAsaGp1c3QgPSAwLjUsdmp1c3QgPSAwLjUpCn0KCmBgYAoKYGBge3IgZmlnLndpZHRoPTE1LGZpZy5oZWlnaHQ9MjV9Cmdnc2F2ZSgiLi9yZXZpc2VkX2ZpZ3VyZXMvQ2FyREVDX21vbm9jeXRlX1N1cHBfZmlnNS5wZGYiLHAsd2lkdGggPSAxNSxoZWlnaHQgPSAyNSkKZ2dzYXZlKCIuL3JldmlzZWRfZmlndXJlcy9DYXJERUNfbW9ub2N5dGVfU3VwcF9maWc1LnRpZmYiLHAsd2lkdGggPSAxNSxoZWlnaHQgPSAyNSxjb21wcmVzc2lvbj0ibHp3IikKcApgYGAKCgozLiBtb25vY2xlcycgVU1BUCBiYXNlZCBvbiBkaWZmZXJlbnQgbWV0aG9kcycgbGF0ZW50CgoKYGBge3J9CmZpZ193aWR0aD0xNQpmaWdfaGVpZ2h0PTI1CmxhYmVscz1sZXR0ZXJzWzE6MTNdCk1ldGhvZHM9YygiUmF3IGNvdW50IEhWR3MiLCJSYXcgY291bnQgQWxsIiwiQ2FyREVDIChsYXRlbnQpIiwiQ2FyREVDIChkZW5vaXNlZCBIVkdzKSIsIkNhckRFQyAoZGVub2lzZWQgQWxsKSIsInNjVkkgKGxhdGVudCkiLCJzY1ZJIChkZW5vaXNlZCBIVkdzKSIsInNjVkkgKGRlbm9pc2VkIEFsbCkiLCJEQ0EgKGxhdGVudCkiLCJEQ0EgKGRlbm9pc2VkIEhWR3MpIiwiRENBIChkZW5vaXNlZCBBbGwpIiwiTU5OIChkZW5vaXNlZCBIVkdzKSIsIk1OTiAoZGVub2lzZWQgQWxsKSIsIlNjYW5vcmFtYSAobGF0ZW50KSIsIlNjYW5vcmFtYSAoZGVub2lzZWQgSFZHcykiLCJTY2Fub3JhbWEgKGRlbm9pc2VkIEFsbCkiKQp1c2VfaWQ9YygzLDE0LDksNiwxKQpnZXRfZHJhd19wbG90PWZ1bmN0aW9uKHBsb3RfaWQ9MSxwbGlzdDApewogIHg9MC4wMgogIHk9MS1wbG90X2lkLzUKICB3aWR0aD0wLjk4CiAgaGVpZ2h0PTEvNS0wLjAxICMgdG90YWwgbnVtYmVyIG9mIGZpZ3VyZXMgaXMgMTIKICBwcD1kcmF3X3Bsb3QoZWdnOjpnZ2FycmFuZ2UocGxvdHM9cGxpc3QwLG5yb3cgPSAxLGRyYXcgPSBGLG5ld3BhZ2UgPSBGKSx4ID0geCx5ID0geSx3aWR0aCA9IHdpZHRoLGhlaWdodCA9IGhlaWdodCkKICAjZHJhd19sYWJlbChsYWJlbHNbcGxvdF9pZF0seD14LHk9eSsxLzYsaGp1c3QgPTEsdmp1c3QgPSAwLjUsc2l6ZSA9IDM1KQogIHJldHVybihwcCkKfQoKZ2V0X2xhYmVsX3Bvcz1mdW5jdGlvbihwbG90X2lkPTEpewogIHg9MAogIHk9MS1wbG90X2lkLzUKICAjZHJhd19sYWJlbChsYWJlbHNbcGxvdF9pZF0seD14LHk9eSsxLzYsaGp1c3QgPTEsdmp1c3QgPSAwLjUsc2l6ZSA9IDM1KQogIHJldHVybihjKHgseSsxLzUtMS8xMDApKQp9CgpnZXRfdGl0bGVfcG9zPWZ1bmN0aW9uKHBsb3RfaWQ9MSl7CiAgeD0wLjAxNQogIHk9MS1wbG90X2lkLzUKICAjZHJhd19sYWJlbChsYWJlbHNbcGxvdF9pZF0seD14LHk9eSsxLzYsaGp1c3QgPTEsdmp1c3QgPSAwLjUsc2l6ZSA9IDM1KQogIHJldHVybihjKHgseSsxLzEwLTEvMTAwKSkKfQpnZXRfcGxvdF9saXN0PWZ1bmN0aW9uKHgseSl7CiAgeDA9cmVwKGxpc3QoKSxsZW5ndGg9bGVuZ3RoKHgpK2xlbmd0aCh5KSkKICB4MFsxOmxlbmd0aCh4KV09eFsxOjNdCiAgeDBbKGxlbmd0aCh4KSsxKTpsZW5ndGgoeDApXT15WzE6Ml0KICByZXR1cm4oeDApCn0KCnA9Z2dkcmF3KCkKZm9yKGkgaW4gMTpsZW5ndGgodXNlX2lkKSl7CiAgcD1wK2dldF9kcmF3X3Bsb3QoaSxnZXRfcGxvdDRfc2VwKGRmX3BzZXVkb3RpbWVfbGlzdFtbdXNlX2lkW2ldXV0pW2MoMSwyKV0pCn0KCmZvciAoaSBpbiAxOmxlbmd0aCh1c2VfaWQpKXsKICBwPXArZHJhd19sYWJlbChsYWJlbHNbaV0seD1nZXRfbGFiZWxfcG9zKGkpWzFdLHk9Z2V0X2xhYmVsX3BvcyhpKVsyXSxzaXplPTMwLGNvbG9yPSJibGFjayIsaGp1c3QgPSAwLHZqdXN0ID0gMSkrCiAgICBkcmF3X2xhYmVsKHBhc3RlMChNZXRob2RzW3VzZV9pZFtpXV0sY29sbGFwc2UgPSAiIiksCiAgICAgICAgICAgICAgIHg9Z2V0X3RpdGxlX3BvcyhpKVsxXSwKICAgICAgICAgICAgICAgeT1nZXRfdGl0bGVfcG9zKGkpWzJdLAogICAgICAgICAgICAgICBzaXplPTIwLAogICAgICAgICAgICAgICBjb2xvciA9ICJibGFjayIsYW5nbGUgPSA5MCxoanVzdCA9IDAuNSx2anVzdCA9IDAuNSkKfQoKYGBgCgpgYGB7ciBmaWcud2lkdGg9MTUsZmlnLmhlaWdodD0yNX0KZ2dzYXZlKCIuL3JldmlzZWRfZmlndXJlcy9DYXJERUNfbW9ub2N5dGVfU3VwcF9maWc2LnBkZiIscCx3aWR0aCA9IDE1LGhlaWdodCA9IDI1KQpnZ3NhdmUoIi4vcmV2aXNlZF9maWd1cmVzL0NhckRFQ19tb25vY3l0ZV9TdXBwX2ZpZzYudGlmZiIscCx3aWR0aCA9IDE1LGhlaWdodCA9IDI1LGNvbXByZXNzaW9uPSJsenciKQpwCmBgYAoKNC4gQ29tYmluZWQgYWJvdmUgdGhyZWUgZmlndXJlcwoKYGBge3J9CmZpZ193aWR0aD0yNApmaWdfaGVpZ2h0PTM2IwpsYWJlbHM9bGV0dGVyc1sxOjE2XQpNZXRob2RzPWMoIlJhdyBjb3VudCBIVkdzIiwiUmF3IGNvdW50IEFsbCIsIkNhckRFQyAobGF0ZW50KSIsIkNhckRFQyAoZGVub2lzZWQgSFZHcykiLCJDYXJERUMgKGRlbm9pc2VkIEFsbCkiLCJzY1ZJIChsYXRlbnQpIiwic2NWSSAoZGVub2lzZWQgSFZHcykiLCJzY1ZJIChkZW5vaXNlZCBBbGwpIiwiRENBIChsYXRlbnQpIiwiRENBIChkZW5vaXNlZCBIVkdzKSIsIkRDQSAoZGVub2lzZWQgQWxsKSIsIk1OTiAoZGVub2lzZWQgSFZHcykiLCJNTk4gKGRlbm9pc2VkIEFsbCkiLCJTY2Fub3JhbWEgKGxhdGVudCkiLCJTY2Fub3JhbWEgKGRlbm9pc2VkIEhWR3MpIiwiU2Nhbm9yYW1hIChkZW5vaXNlZCBBbGwpIikKdXNlX2lkPWMoMSwzOjUsMTQ6MTYsNjoxMykKZ2V0X2RyYXdfcGxvdD1mdW5jdGlvbihwbG90X2lkPTEscGxpc3QwKXsKICB4PWlmZWxzZShwbG90X2lkJSUyPT0xLDAsMC41MDc1KQogIHk9MS1mbG9vcigocGxvdF9pZCsxKS8yKS84CiAgd2lkdGg9MS8yLTAuMDE1CiAgaGVpZ2h0PTEvOC0wLjAxICMgdG90YWwgbnVtYmVyIG9mIGZpZ3VyZXMgaXMgMTIKICBwcD1kcmF3X3Bsb3QoZWdnOjpnZ2FycmFuZ2UocGxvdHM9cGxpc3QwLG5jb2wgPSAyLGRyYXcgPSBGLG5ld3BhZ2UgPSBGKSx4ID0geCx5ID0geSx3aWR0aCA9IHdpZHRoLGhlaWdodCA9IGhlaWdodCkKICAjZHJhd19sYWJlbChsYWJlbHNbcGxvdF9pZF0seD14LHk9eSsxLzYsaGp1c3QgPTEsdmp1c3QgPSAwLjUsc2l6ZSA9IDM1KQogIHJldHVybihwcCkKfQoKZ2V0X2xhYmVsX3Bvcz1mdW5jdGlvbihwbG90X2lkPTEpewogIHg9aWZlbHNlKHBsb3RfaWQlJTI9PTEsMCwwLjUwNzUpCiAgeT0xLWZsb29yKChwbG90X2lkKzEpLzIpLzgKICAjZHJhd19sYWJlbChsYWJlbHNbcGxvdF9pZF0seD14LHk9eSsxLzYsaGp1c3QgPTEsdmp1c3QgPSAwLjUsc2l6ZSA9IDM1KQogIHJldHVybihjKHgseSsxLzgtMS8xMDApKQp9CgpnZXRfdGl0bGVfcG9zPWZ1bmN0aW9uKHBsb3RfaWQ9MSl7CiAgeD1pZmVsc2UocGxvdF9pZCUlMj09MSwwLDAuNTA3NSkrMC41LzIKICB5PTEtZmxvb3IoKHBsb3RfaWQrMSkvMikvOAogICNkcmF3X2xhYmVsKGxhYmVsc1twbG90X2lkXSx4PXgseT15KzEvNixoanVzdCA9MSx2anVzdCA9IDAuNSxzaXplID0gMzUpCiAgcmV0dXJuKGMoeCx5KzEvOC0xLzMwMCkpCn0KCnA9Z2dkcmF3KCkKZm9yKGkgaW4gMTpsZW5ndGgodXNlX2lkKSl7CiAgcD1wK2dldF9kcmF3X3Bsb3QoaSxnZXRfcGxvdDRfc2VwKGRmX3BzZXVkb3RpbWVfbGlzdFtbdXNlX2lkW2ldXV0pW2MoMSwyKV0pCn0KCmZvciAoaSBpbiAxOmxlbmd0aCh1c2VfaWQpKXsKICBwPXArZHJhd19sYWJlbChsYWJlbHNbaV0seD1nZXRfbGFiZWxfcG9zKGkpWzFdLHk9Z2V0X2xhYmVsX3BvcyhpKVsyXSxzaXplPTE4LGNvbG9yPSJibGFjayIsaGp1c3QgPSAwLHZqdXN0ID0gMSkrCiAgICBkcmF3X2xhYmVsKHBhc3RlMChNZXRob2RzW3VzZV9pZFtpXV0sY29sbGFwc2UgPSAiIikseD1nZXRfdGl0bGVfcG9zKGkpWzFdLHk9Z2V0X3RpdGxlX3BvcyhpKVsyXSxzaXplPTI1LGNvbG9yID0gImJsYWNrIix2anVzdCA9IDEpCn0KCmBgYAoKYGBge3IgZmlnLndpZHRoPTI0LGZpZy5oZWlnaHQ9MzZ9CnAKYGBgCgpgYGB7cn0KZ2dzYXZlKHAsZmlsZW5hbWUgPSAiLi9yZXZpc2VkX2ZpZ3VyZXMvQ2FyREVDX21vbm9jeXRlX1N1cHBfZmlnNDU2X2NvbWJpbmVkLnBkZiIsd2lkdGggPSAyNCxoZWlnaHQgPSAzNikKZ2dzYXZlKHAsZmlsZW5hbWUgPSAiLi9yZXZpc2VkX2ZpZ3VyZXMvQ2FyREVDX21vbm9jeXRlX1N1cHBfZmlnNDU2X2NvbWJpbmVkLnRpZmYiLHdpZHRoID0gMjQsaGVpZ2h0ID0gMzYsY29tcHJlc3Npb249Imx6dyIpCmBgYAoKCmBgYHtyfQojc2F2ZSBvYmplY3QgCnJtKG10eCkKcm0ob3V0cHV0KQpybShhZGF0YSkKcm0oY2RzKQpybShvYmowKQpybShyYXcuZGF0YSkKZ2MoKQpzYXZlLmltYWdlKGZpbGU9ImNhckRFQ19tb25vY3l0ZV9maW5hbF9yZXZpc2VkLlJEYXRhIikjaW5jbHVkZSBzY2Fub3JhbWEsY2FyREVDX21vbm9jeXRlX2ZpbmFsLlJEYXRhIG5vdCBpbmNsdWRlIHNjYW5vcmFtYQojbG9hZCgiY2FyREVDX21vbm9jeXRlX2ZpbmFsX3JldmlzZWQuUkRhdGEiKQpgYGAKCmBgYHtyfQojbG9hZCgiY2FyREVDX21vbm9jeXRlX2ZpbmFsX3JldmlzZWQuUkRhdGEiKQpgYGAKCmBgYHtyfQpzZXNzaW9uSW5mbygpCmBgYAo=